再读多线程
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了再读多线程相关的知识,希望对你有一定的参考价值。
一,概念
当代操作系统中,可以独立并发执行的基本单元。
轻量:占用系统资源少
独立:操作系统中可以陆地调度和分派的基本单位
共享:共享进程中的资源
二,实现线程
更推荐集成Runnable接口方式?
三,线程生命周期
新建:线程刚刚创建完毕
可运行:启动线程后
运行:操作系统调度中
阻塞/等待:等待资源或者时间片
消亡:退出run方法
四,常用API
静态 针对当前进程
currentThread
yield
sleep
实例方法 针对指定线程
start
setPriority/getPriority(1-10 不设置是5 不一定高优先级就能先执行)
setName/getName
setDaemon/isDaemon(守护线程是其他线程结束之后自动消亡的线程)
五,线程同步
/* * DESCRIPTION : * USER : zhouhui * DATE : 2017/8/1 15:50 */ public class SynchronizedTest { /** * method1:对方法进行锁 */ public synchronized void method1(){ } /** * method2:对当前对象锁 */ public void method2(){ synchronized (this){ } } /** *method3:对当前对象锁 */ public void method3(){ synchronized (SynchronizedTest.this){ } } /** *method4:对静态方法锁 * 静态方法属于类,所以是对类上锁 */ public synchronized static void method4(){ } /** *method5:对class锁 */ public static void method5(){ synchronized (SynchronizedTest.class){ } } /** * method6:对成员变量锁 */ private Integer i = 0; public void method6(){ synchronized (i){ } } }
Java语法规定,任何线程执行同步方法、同步代码块 之前,必须先获取对应的监视器。
其中method1,method2,method3都是对当前对象上锁。
method4,method5对当前类上锁
method6是对属性上锁。
对方法上锁和对代码块上锁的区别是,如果方法太大,对方法上锁的开销要大的多。
method2和method6的区别:
public class Test { public static void main(String[] args) { Data data = new Data(); new Thread(new MyRunnable(data),"A").start(); new Thread(new MyRunnable(data),"B").start(); } } class Data{ private Integer i = 0; public void show(){ while (true){ synchronized (i){ if(i == 30){ break; } System.out.println(Thread.currentThread().getName() + " Before :" + i); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } i ++; System.out.println(Thread.currentThread().getName() + " After :" + i); } } } } class MyRunnable implements Runnable{ private Data data; public MyRunnable(Data data){ this.data = data; } public void run() { data.show(); } }
synchronized (i){
和
synchronized (this){
会产生不同的结果。
对this上锁能够正常的在30时停止,对i上锁会打印如下:
A Before :0 A After :1 B Before :1 A Before :1 A After :2 A Before :2 B After :3 B Before :3 B After :4 A After :5 B Before :5 B After :6 B Before :6 A Before :6 A After :7 A Before :7 B After :8 B Before :8 B After :9 A After :9 B Before :9 B After :10 B Before :10 A Before :10 A After :11 A Before :12 B After :12 A After :13 B Before :13 A Before :13 A After :15 B After :15 A Before :15 A After :16 B Before :16 A Before :16 A After :17 A Before :17 B After :18 B Before :18 A After :19 A Before :19 B After :20 B Before :20 A After :21 A Before :21 B After :22 B Before :22 A After :23 A Before :23 B After :24 B Before :24 A After :25 A Before :25 B After :26 B Before :26 A After :27 A Before :27 B After :28 B Before :28 A After :29 A Before :29 B After :30 A After :31 A Before :31 A After :32 A Before :32 A After :33 A Before :33 A After :34 A Before :34 A After :35 A Before :35
但是有时候是可以成功的。
如果对i上锁,能够保证同一时间只能一个线程对i进行操作。如果一个线程能够在另外一个线程i++之前获得i那么,他是能够正常i==30停止的,但是如果在另外一个线程i++之后获得i那么,他就会直接跳过30,而继续运行。
对this上锁,意味着对整个对象上锁,只能一个线程操作代码块,保证数据的完整性。
六,线程间通信
Object对象提供了wait() notify() notifyAll()方法,被所有子类继承。
wait()获得当前对象锁的线程,释放掉当前的锁,无限期的等待,必须被其他的线程唤醒。
notify() 唤醒任意一个waiting的线程到ready状态,是否变成running状态,还需要线程调度器的调度。
notifyAll()唤醒所有的waiting的线程到ready状态。
线程间的通信其实就是停止和唤醒的过程。
以下代码实现两个线程对同一个对象的+1和-1操作,相互停止和唤醒。
/* * DESCRIPTION : * USER : zhouhui * DATE : 2017/8/1 17:28 */ public class NumberHolder { private int number; public synchronized void increase() { if (0 != number) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 能执行到这里说明已经被唤醒 // 并且number为0 number++; System.out.println(number); // 通知在等待的线程 notify(); } public synchronized void decrease() { if (0 == number) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 能执行到这里说明已经被唤醒 // 并且number不为0 number--; System.out.println(number); notify(); } } class IncreaseThread extends Thread { private NumberHolder numberHolder; public IncreaseThread(NumberHolder numberHolder) { this.numberHolder = numberHolder; } @Override public void run() { for (int i = 0; i < 20; ++i) { // 进行一定的延时 try { Thread.sleep((long) Math.random() * 1000); } catch (InterruptedException e) { e.printStackTrace(); } // 进行增加操作 numberHolder.increase(); } } } class DecreaseThread extends Thread { private NumberHolder numberHolder; public DecreaseThread(NumberHolder numberHolder) { this.numberHolder = numberHolder; } @Override public void run() { for (int i = 0; i < 20; ++i) { // 进行一定的延时 try { Thread.sleep((long) Math.random() * 1000); } catch (InterruptedException e) { e.printStackTrace(); } // 进行减少操作 numberHolder.decrease(); } } } class NumberTest { public static void main(String[] args) { NumberHolder numberHolder = new NumberHolder(); Thread t1 = new IncreaseThread(numberHolder); Thread t2 = new DecreaseThread(numberHolder); t1.start(); t2.start(); } }
打印结果:
1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
以上是关于再读多线程的主要内容,如果未能解决你的问题,请参考以下文章
再读《Parallel Programming with Python》并作笔记
newCacheThreadPool()newFixedThreadPool()newScheduledThreadPool()newSingleThreadExecutor()自定义线程池(代码片段