百知教育 - 孙帅 - 16_多线程
01_线程的概念和实现线程的方式
-
什么是进程
- 程序是静止的,只有真正运行时的程序,才被称为进程。
- 单核CPU在任何时间点上,只能运行一个进程;宏观并行、微观串行。
-
什么是线程
- 线程,又称为 轻量级进程(Light Weight Process)。 是程序中的 一个顺序控制流程,同时也是 CPU的基本调度单位。进程由多个线程组成,彼此间完成不同的工作, 交替执行,称为多线程。
-
线程的组成
- CPU时间片: 操作系统(OS) 会为每个线程分配执行时间
- 运行数据:
- 堆空间: 存储线程需使用的对象,多个线程可以共享堆中的对象。
- 栈空间: 存储线程需使用的局部变量,每个线程都拥有独立的栈。
- 线程的逻辑代码
-
代码:
package day19; public class TestThread{ public static void main(String[] args){ Task1 task1 = new Task1(); Thread t1 = new Thread(task1); t1.start(); Thread t2 = new TaskThread(); //Thread类实现了Runnable接口,本身可以充当线程的任务 t2.start(); } } class Task1 implements Runnable{ public void run(){ for(int i = 0; i < 10; i++){ System.out.println("@@@ "+i); } } } class TaskThread extends Thread{ public void run(){ for(int i = 0; i < 10; i++){ System.out.println("### "+i); } } }
-
运行结果:
02_Thread的基本状态
-
new 初始状态
线程对象被创建,即为初始状态。在堆中开辟内存,与常规对象无异。 -
Ready 就绪状态
调用start() 之后,进入就绪状态,等待OS选中,并分配时间片。 -
Running 运行状态
获得时间片后,进入运行状态 ,如果时间片到期,则回到就绪状态。 -
Terminated 终止状态
主线程main()或独立线程run()结束,进入终止状态,并释放持有的时间片。 -
总结:
- 实际上,就绪状态与运行状态统称为Runnable
- 可通过设置线程的优先级,保证其执行的顺序:
Thread t1 = new Thread(task1); t1.setPriority(10); //1~10优先级越来越高
。但是由于Java的跨平台性,不同的操作系统会有不同的线程调度策略,对于其他操作系统优先级可能不会发挥作用。
03_线程的等待状态
-
方法:
- Thread.sleep() 限时等待,线程进入休眠状态,会抛出**InterruptedException异常**。
- Thread.yield() 放弃CPU,回到就绪状态。
- setDaemon(true) 设置线程为 守护线程 ,不论该线程是否结束,当所有的非守护线程都结束时,进程就会结束。
- t.join() 当前线程进入等待状态,直到 t 线程终止,才会恢复执行,会抛出异常。
- Thread.currentThread() 获得当前线程
- t.getName() 获得 t 线程的名字(创建线程对象时可以传入一个字符串,当做线程的名字,否则取默认名字)
-
代码:
package day19; public class TestThread1{ public static void main(String[] args){ Thread t1 = new Thread(new TaskA()); Thread t2 = new ThreadB(); t2.setDaemon(true); t1.start(); t2.start(); /* t1.join(); t2.join(); System.out.println(Thread.currentThread().getName()); System.out.println("All Thread is Over"); */ } } class TaskA implements Runnable{ public void run(){ for(int i = 1; i <= 10; i++){ System.out.println(i); try{ Thread.sleep(100); }catch(InterruptedException e){ e.printStackTrace(); } } } } class ThreadB extends Thread{ public void run(){ for(char c = 'A'; c <= 'N'; c++){ System.out.println(c); System.out.println(Thread.currentThread().getName()); try{ Thread.sleep(500); }catch(InterruptedException e){ e.printStackTrace(); } } } }
-
运行结果:
04_线程安全的问题
- 当多线程共同访问同一个对象(临界资源)的时候,如果破坏了不可分割的操作(原子操作),就可能发生 数据不一致。
-
代码:
package day19; public class TestSynchronization{ public static void main(String[] args) throws Exception{ MyList list = new MyList(); Thread t1 = new Thread(new Runnable(){ public void run(){ list.add("C"); } }); Thread t2 = new Thread(new Runnable(){ public void run(){ list.add("D"); } }); t1.start(); t2.start(); t1.join(); t2.join(); list.print(); } } class MyList{ String[] s = {"A","B","","","",""}; int index = 2; public void add(String s1){ s[index] = s1; try{ Thread.sleep(100); }catch(InterruptedException e){ e.printStackTrace(); } index++; } public void print(){ for(int i = 0; i < s.length; i++){ System.out.println(s[i]); } } }
-
运行结果:
05_同步代码块
- 每个Java对象都有一个互斥锁标记,用来分配给线程
- synchronized(o){ //代码块 } 对o对象加锁的 同步代码块 ,只有拿到o的 锁标记 的线程,才能进入对o加锁的同步代码块。
-
修改上面代码为:
synchronized(list){ list.add("C"); } synchronized(list){ list.add("D"); }
-
运行结果:
06_同步方法和死锁
-
synchronized
方法修饰符,表示对this加锁的同步代码块。只有拿到this的锁标记的线程,才能调用this的同步方法。 -
修改上上代码为(结果正确):
public synchronized void add(String s){ //代码块 }
07_等待-通知机制
-
线程通信机制:
等待-通知机制 -
o.wait():
必须 出现在对o加锁的同步代码块里 ,执行后线程会释放锁标记,进入等待状态(进入o的等待队列) -
o.notify()/notifyAll():
必须 出现在对o加锁的同步代码块里 ,执行后从等待状态(o的等待队列)中释放一个/全部线程 -
代码:
package day20; public class TestWaitNotify{ public static void main(String[] args) throws Exception{ Object o = new Object(); Thread t = new Thread(new Runnable(){ public void run(){ synchronized(o){ System.out.println("A"); System.out.println("B"); o.notify(); System.out.println("C"); System.out.println("D"); } } }); t.start(); synchronized(o){ System.out.println("1"); System.out.println("2"); o.wait(); System.out.println("3"); System.out.println("4"); } } }
-
运行结果:
08_生产者消费者
-
代码:
package day20; public class TestProducerConsumer{ public static void main(String[] args){ MyStack stack = new MyStack(); Runnable task1 = new Runnable(){ public void run(){ for(char c = 'A'; c <= 'I'; c++){ stack.push(c+""); } } }; Runnable task2 = new Runnable(){ public void run(){ for(int i = 1; i <= 9; i++){ stack.pop(); } } }; new Thread(task1).start(); //new Thread(task1).start(); new Thread(task2).start(); //new Thread(task2).start(); } } class MyStack{ String[] data = {"","","","","",""}; int index; public synchronized void push(String s){ while(index == data.length){ try{ this.wait(); }catch(InterruptedException e){ e.printStackTrace(); } } data[index] = s; index++; System.out.print(s+" pushed "); print(); this.notifyAll(); } public synchronized void pop(){ while(index == 0){ try{ this.wait(); }catch(InterruptedException e){ e.printStackTrace(); } } index--; String s = data[index]; data[index] = ""; System.out.print(s+" poped "); print(); this.notifyAll(); } public void print(){ for(int i = 0; i < data.length; i++){ System.out.print(data[i]+" "); } System.out.println(); } }
-
运行结果:
09_数字和字母的交替打印
-
代码:
package day20; public class TestNumberCharPrint{ public static void main(String[] args){ Object o = new Object(); Runnable task1 = new Runnable(){ public void run(){ synchronized(o){ for(int i = 1; i <= 10; i++){ System.out.println(i); if(i % 2 == 0){ o.notifyAll(); try{ if(i != 10) o.wait(); }catch(InterruptedException e){ e.printStackTrace(); } } } } } }; Runnable task2 = new Runnable(){ public void run(){ synchronized(o){ for(char c = 'A'; c <= 'E'; c++){ System.out.println(c); o.notifyAll(); try{ if(c != 'E') o.wait(); }catch(InterruptedException e){ e.printStackTrace(); } } } } }; Thread t1 = new Thread(task1); Thread t2 = new Thread(task2); t1.start(); t2.start(); } }
-
运行结果:
10_线程池
-
代码:
package day20; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class TestExecutor{ public static void main(String[] args){ ExecutorService es = Executors.newFixedThreadPool(2); //ExecutorService es = Executors.newCachedThreadPool(); Runnable r1 = new Runnable(){ public void run(){ for(int i = 0; i < 10; i++){ System.out.println("### "+i); try{ Thread.sleep(100); }catch(InterruptedException e){ e.printStackTrace(); } } } }; Runnable r2 = new Runnable(){ public void run(){ for(int i = 0; i < 10; i++){ System.out.println("@@@ "+i); try{ Thread.sleep(100); }catch(InterruptedException e){ e.printStackTrace(); } } } }; Runnable r3 = new Runnable(){ public void run(){ for(int i = 0; i < 10; i++){ System.out.println("$$$ "+i); try{ Thread.sleep(100); }catch(InterruptedException e){ e.printStackTrace(); } } } }; es.submit(r1); es.submit(r2); es.submit(r3); es.shutdown(); } }
-
运行结果:
11_Callable和Future
-
代码:
package day20; import java.util.concurrent.Executors; import java.util.concurrent.ExecutorService; import java.util.concurrent.Callable; import java.util.concurrent.Future; public class TestCallable{ public static void main(String[] args) throws Exception{ ExecutorService es = Executors.newCachedThreadPool(); Callable<Integer> task1 = new Callable<Integer>(){ public Integer call() throws Exception{ System.out.println("task1 starts"); int result = 0; for(int i = 1; i < 100; i += 2){ result += i; Thread.sleep(100); } System.out.println("task1 ends"); return result; } }; Callable<Integer> task2 = new Callable<Integer>(){ public Integer call() throws Exception{ System.out.println("task2 starts"); int result = 0; for(int i = 2; i <= 100; i += 2){ result += i; Thread.sleep(100); } System.out.println("task2 ends"); return result; } }; Future<Integer> f1 = es.submit(task1); Future<Integer> f2 = es.submit(task2); System.out.println("main do sth"); int result = f1.get()+f2.get(); System.out.println(result); es.shutdown(); } }
-
运行结果:
12_Lock对象
-
Lock接口
- JDK5加入,与synchronized比较,显示定义,结构更灵活。
- 提供更多实用性方法,功能更强大、性能更优越。
- 常用方法:
- void lock(): //获取锁,如锁被占用,则等待。
- boolean tryLock(): //尝试获取锁(成功返回true,失败返回false,不阻塞)
- void unlock(): //释放锁
-
代码:
package day20; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class TestLock{ public static void main(String[] args) throws Exception{ MyList list = new MyList(); Thread t1 = new Thread(new Runnable(){ public void run(){ list.add("C"); } }); Thread t2 = new Thread(new Runnable(){ public void run(){ list.add("D"); } }); t1.start(); t2.start(); t1.join(); t2.join(); list.print(); } } class MyList{ String[] s = {"A","B","","","",""}; int index = 2; Lock lock = new ReentrantLock(); public void add(String s1){ try{ //lock.tryLock(); lock.lock(); s[index] = s1; try{ Thread.sleep(100); }catch(InterruptedException e){ e.printStackTrace(); } index++; } finally{ lock.unlock(); } } public void print(){ for(int i = 0; i < s.length; i++){ System.out.println(s[i]); } } }
-
运行结果:
13_Condition对象
-
代码:
package day20; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class TestProducerConsumerLock{ public static void main(String[] args){ MyStack stack = new MyStack(); Runnable task1 = new Runnable(){ public void run(){ for(char c = 'A'; c <= 'I'; c++){ stack.push(c+""); } } }; Runnable task2 = new Runnable(){ public void run(){ for(int i = 1; i <= 9; i++){ stack.pop(); } } }; new Thread(task1).start(); //new Thread(task1).start(); new Thread(task2).start(); //new Thread(task2).start(); } } class MyStack{ String[] data = {"","","","","",""}; int index; Lock lock = new ReentrantLock(); Condition full = lock.newCondition(); Condition empty = lock.newCondition(); public void push(String s){ try{ lock.lock(); while(index == data.length){ try{ full.await(); }catch(InterruptedException e){ e.printStackTrace(); } } data[index] = s; index++; System.out.print(s+" pushed "); print(); empty.signalAll(); } finally{ lock.unlock(); } } public void pop(){ try{ lock.lock(); while(index == 0){ try{ empty.await(); }catch(InterruptedException e){ e.printStackTrace(); } } index--; String s = data[index]; data[index] = ""; System.out.print(s+" poped "); print(); full.signalAll(); } finally{ lock.unlock(); } } public void print(){ for(int i = 0; i < data.length; i++){ System.out.print(data[i]+" "); } System.out.println(); } }
-
运行结果: