线程
- 程序、进程、线程
 
程序(program):是为完成特定任务、用某种语言编写的一组指令的集合。
即指一端静态的代码。
进程(process):指正在执行的程序,从Windows角度讲,进程是操作系统进行资源分配的最小单位。
线程(thread):进程可进一步细化为线程,是一个进程内部的最小执行单元,是操作系统进行任务调度的最小单元,隶属于进程。
- 线程和进程的关系
 
- 创建线程
 
- 继承Thread类的方式(类就不能继承其他类); 
package Thread.Demo01; /* 继承Thread类 类就不能继承其他类 */ public class MyThread extends Thread{ @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println("MyThread:"+i); } } public static void main(String[] args) { //创建线程 MyThread myThread = new MyThread(); myThread.start(); System.out.println("结束"); } }运行结果:
结束 MyThread:0 MyThread:1 MyThread:2 MyThread:3 MyThread:4 MyThread:5 MyThread:6 MyThread:7 MyThread:8 MyThread:9 - 实现Runnable接口的方式(类还可以继承其他类); 
package Thread.Demo01; /* 实现Thread接口 类还可以继承其他类 重写run() 这个类可以成为线程任务类 Thread.currentThread() 获得当前正在执行的线程对象 */ public class ThreadDemo implements Runnable{ @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println("ThreadDemo:"+i); //System.out.println(Thread.currentThread().getName(); } } public static void main(String[] args) { //创建线程执行任务 ThreadDemo threadDemo = new ThreadDemo(); //创建线程 Thread t = new Thread(threadDemo); //定义线程名称 //Thread t = new Thread(threadDemo,"自定义线程"); //启动线程 t.start(); for (int i = 0; i < 10; i++) { System.out.println("main:"+i); } } }运行结果:
main:0 main:1 main:2 ThreadDemo:0 ThreadDemo:1 ThreadDemo:2 ThreadDemo:3 ThreadDemo:4 ThreadDemo:5 ThreadDemo:6 main:3 ThreadDemo:7 ThreadDemo:8 ThreadDemo:9 main:4 main:5 main:6 main:7 main:8 main:9 - 继承方式和实现方式的联系和区别:
 -  
【区别】
【实现Runnable的好处】
 - 避免了单继承的局限性;
 - 多个线程可以共享同一个接口实现类的对象,非常适合多个相同线程来处理同一份资源。
 
- Thread类中的方法
 
- Thread类构造方法:
 
-  
  
构造方法
说明
Thread()
创建一个新的线程
Thread(String name)
创建一个指定名称的线程
Thread(Runnable target)
利用Runnable对象创建一个线程,启动时将执行该对象的run方法。
Thread(Runnable target,String name)
利用Runnable对象创建一个线程,并指定该线程的名称。
 
2.Thread类常用方法:
|   Void start()  |   启动线程  | 
|   Final void setName(String name)  |   设置线程的名称  | 
|   Final String getName()  |   返回线程的名称  | 
|   Final void setPriority(int newPriority)  |   设置线程的优先级  | 
|   Final int getPriority()  |   返回线程的优先级  | 
|   Final void join() throws InterruptedException  |   等待线程终止  | 
|   static Thread currentThread()  |   返回对当前正在执行的线程对象的引用  | 
|   static void sleep(long millis) throws InterruptedException  |   让当前正在执行的线程休眠(暂停执行) 休眠时间由millis(毫秒)指定  | 
- 线程优先级
 
- 线程状态
 

线程的状态:
代码:
    package Thread.Demo02;
public class ThreadDemo extends Thread {
    
    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
//            try {
//                //让线程休眠指定的时间
//                Thread.sleep(1000);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
            if (i%10==0){
                //线程让步
                Thread.yield();
            }
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }
    public static void main(String[] args) throws InterruptedException {
        ThreadDemo t = new ThreadDemo();
                   t.start();
                   //等待该线程结束(把其他线程加入到此线程,让其他线程阻塞)
                   t.join();
        for (int i = 0; i < 1000; i++) {
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }
} 
 
 
- 线程的分类
 
守护线程:一直执行,必须在启动前设置,在所有的用户线程结束后自动结束,如垃圾回收线程;
用户线程
- 多线程的概念
 
- 多线程:
 
指程序中包含多个执行单元,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,也就是说允许单个 线程创建多个并行线程来完成各自的任务;
- 何时需要多线程:
 
- 多线程的优点:
 
- 多线程的缺点:
 
- 多线程何时产生问题:多个线程,访问的是同一个共享资源(数据);
 - 多个线程访问共享资源出现问题的本质在于CPU是多核的,理论上是可以同时执行多个线程。
 
- 线程同步
 
并行:在同一个时间,同时做多个事情
例如:360同时做多件事情;
并发:在一段时间内,依次做多件事情 并发执行,交替执行;
多线程同步:线程排队 + 锁
确保一个时间点只有一个线程访问共享资源,可以给共享资源加一把锁,哪个线程获取了这把锁,才有权访问该资源。
每个类被加载到内存中时,都会为该类创建一个class类对象,用于封装类的信息,一个类即使创建多个对象,class类的对象只有一个;
案例:买票机制
package Thread.Demo03;
/*
  模拟买票线程
 */
public class TicketThread extends Thread{
    //10张票   加static表示共享资源,只有一份
    static int num = 10;
    static Object lockFlog = new Object();
    @Override
    public void run() {
        while (true) {
            /*
            if(num > 0) {
                try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
                 */
            /*
                synchronized(锁对象) {
                    同步代码
                }
                锁对象可以是任何对象,但是对于多个线程必须是同一个.
                在对象中,有一个对象头的区域,在对象头中有一个标志为(锁状态)
                具体实现,由编译后的指令实现控制
             */
            synchronized (lockFlog) {
                if (num > 0) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                        System.out.println(Thread.currentThread().getName() + ":" + num);
                        num--;
                    } else{
                        break;
                    }
                }
            }
        }
    public static void main(String[] args) {
        TicketThread t1 = new TicketThread();
                     t1.setName("窗口1");
        TicketThread t2 = new TicketThread();
                     t2.setName("窗口2");
                     t1.start();
                     t2.start();
    }
} 
运行结果:
运行结果:
窗口1:10
窗口1:9
窗口1:8
窗口1:7
窗口1:6
窗口1:5
窗口1:4
窗口1:3
窗口1:2
窗口2:1 
加锁后:
加锁后:
package Thread.Demo03;
public class TicketThread_back {
    //10张票   加static表示共享资源,只有一份
    static int num = 10;
    static Object lockFlog = new Object();
    public void run() {
        while (true) {
                if (num > 0) {
                    break;
                }
                print();
            }
        }
    public static void main(String[] args) {
        TicketThread t1 = new TicketThread();
        t1.setName("窗口1");
        TicketThread t2 = new TicketThread();
        t2.setName("窗口2");
        t1.start();
        t2.start();
    }
    /*
        synchronized修饰方法时,并没有显示的让我们添加锁的标志对象。
        在修饰非静态方法时,锁标志的对象默认this
        在修饰静态方法时,锁标志对象是class类对象
     */
    public synchronized void print() {
        if (num > 0) {
            try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
              System.out.println(Thread.currentThread().getName() + ":" + num);
              num--;
            }
        }
} 
运行结果:
窗口1:10
窗口2:9
窗口2:8
窗口2:7
窗口2:6
窗口2:5
窗口2:4
窗口2:3
窗口2:2
窗口2:1 
- Lock锁
 
1.java.util.concurrent.locks.Lock接口是控制多个线程对共享资源进行访问的工具。锁提供了对共享资源的独占访问,每次只能有一个线程对Lock对象加锁,线程开始访问共享资源之前应先获得Lock对象。
2.ReentrantLock类实现了Lock,它拥有与synchronized相同的并发性和内存语义,在实现线程安全的控制中,比较常用的是ReentrantLock,可以显式加锁,释放锁;
3.死锁:不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,形成了线程的死锁;
出现死锁后,不会出现异常,不会出现提示,只是所有的线程都处于阻塞状态,无法继续;
package Thread.Demo04;
/*
    线程死锁
    同步代码块中死循环,锁一直释放不了
    同步代码块嵌套,不同线程一直占着对方需要的同步锁不释放
 */
public class ThreadDemo extends Thread {
    static Object obja = new Object();
    static Object objb = new Object();
    boolean flag = true;
    public ThreadDemo(boolean flag) {
        this.flag = flag;
    }
    @Override
    public void run() {
        if (flag) {
            synchronized (obja) {
                System.out.println("if obja");
                synchronized (objb) {
                    System.out.println("if objb");
                }
            }
        } else {
            synchronized (objb) {
                System.out.println("else objb");
                synchronized (obja) {
                    System.out.println("else obja");
                }
            }
        }
    }
    public static void main(String[] args) {
        ThreadDemo d1 = new ThreadDemo(true);
        d1.start();
        ThreadDemo d2 = new ThreadDemo(false);
        d2.start();
    }
} 
多次运行结果:
首次运行:
if obja
if objb
else objb
else obja
二次运行:
else objb
else obja
if obja
if objb
三次运行:
if obja
else objb
(后不再改变) 
 
 
- 线程通信
 
线程通讯:多个线程通过相互牵制,相互调度,即线程间的相互作用。
三个方法:
- 新增创建线程方式
 
实现Callable接口与使用Runnable相比,Callable功能更加强大;
package Thread.Demo07;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class SumThread implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        int num = 0;
        for (int i = 0; i < 100; i++) {
            num += i;
        }
        return num;
    }
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        SumThread sumThread = new SumThread();
        FutureTask<Integer> futureTask = new FutureTask(sumThread);
        Thread t = new Thread(futureTask);
               t.start();
               //获取返回值
               Integer sum = futureTask.get();
               System.out.println(sum);
    }
}
 
运行结果:4950










