多线程-线程内存可见性-线程同步的单例模式

线程同步
可以修饰实例方法,也可以修饰静态方法,还可以修饰代码块,会为代码块加上内置锁,从而实现线程同步 。
在静态方法中添加同步代码块 。
修饰同步代码块,
(){
//
()内部需要设置加锁的资源 , 静态方法属于类的方法,不属于任何一个实例对象,所以静态方法中的()只能锁定类,不能锁定实例对象 , this可以表示当前的一个实例 。
实例方法中也可以使用关键字实现同步代码块 。
先来个案例:
用多线程打印a1-b2-c3-d4-e5 ····· z26
-wait-小应用
写法一:
public class Class01 {private static Object obj = new Object();public static void main(String[] args) {Thread t1 = null, t2 = null;char[] c1 = "abcdefghijklmnopqrstuvwxyz".toCharArray();int[] c2 = new int[26];for (int i = 0; i < 26; i++) {c2[i] = i + 1;}t1 = new Thread(() -> {synchronized (obj) {for (int i = 0; i < c1.length; i++) {System.out.print(c1[i]);try {Thread.currentThread().sleep(1000);} catch (InterruptedException e1) {e1.printStackTrace();}try {obj.notify();obj.wait();} catch (InterruptedException e) {e.printStackTrace();}obj.notify();}}}, "t1");t2 = new Thread(() -> {synchronized (obj) {for (int i = 0; i < c2.length; i++) {if (i == c2.length - 1) {System.out.print(c2[i]);} else {System.out.print(c2[i] + "-");}try {Thread.currentThread().sleep(1000);} catch (InterruptedException e1) {e1.printStackTrace();}try {obj.notify();obj.wait();} catch (InterruptedException e) {e.printStackTrace();}obj.notify();}}}, "t2");if (c1.length == c2.length) {t1.start();t2.start();} else {System.out.println("c1.length 不等于 c2.length");}}}
写法二:
import java.util.concurrent.locks.LockSupport;public class Class02 {// 1A-2B-3C-4Dstatic Thread t12 = null, t22 = null;public static void main(String[] args) {char[] c1 = "abcdefghijklmnopqrstuvwxyz".toCharArray();int[] c2 = new int[26];for (int i = 0; i < 26; i++) {c2[i] = i + 1;}t12 = new Thread(() -> {for (char i : c1) {System.out.print(i);LockSupport.unpark(t22);LockSupport.park();}}, "t1");t22 = new Thread(() -> {for (int i : c2) {LockSupport.park();if (i == c2[c2.length - 1]) {System.out.print(i);} else {System.out.print(i + "-");}LockSupport.unpark(t12);}}, "t2");if (c1.length == c2.length) {t12.start();t22.start();} else {System.out.println("c1.length 不等于 c2.length");}}}
.class:获取的是在内存中的运行时类,每个运行时类只有一份 。
package com.m.test;public class Class03 {public static void main(String[] args) {// 能同步MyRunnable03 myRunnable03 = new MyRunnable03();for (int i = 0; i < 5; i++) {Thread thread = new Thread(myRunnable03);thread.start();}}}
public class MyRunnable03 implements Runnable {@Overridepublic void run() {//synchronized(MyRunnable03.class)synchronized(this) {System.out.println("start...");try {Thread.currentThread().sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("end...");}}}
5个实例化对象
package com.m.test;public class Class01 {public static void main(String[] args) {//能同步for (int i = 0; i < 5; i++) {MyRunnable01 myRunnable01 = new MyRunnable01();Thread thread = new Thread(myRunnable01);thread.start();}}}
public class MyRunnable01 implements Runnable {private static Integer num = 1;@Overridepublic void run() {//num++;synchronized (num) {System.out.println("start...");try {Thread.currentThread().sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("end...");}}}
1个实例化对象
package com.m.test;public class Class02 {public static void main(String[] args) {// 不能同步MyRunnable02 myRunnable02 = new MyRunnable02();for (int i = 0; i < 5; i++) {Thread thread = new Thread(myRunnable02);thread.start();}}}
public class MyRunnable02 implements Runnable {private static Integer num = 1;@Overridepublic void run() {//num++; 判断num是一个还是多个synchronized(num) {System.out.println("start...");try {Thread.currentThread().sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("end...");}}}
单例模式
整个系统中,无论做怎样的业务操作,保证内存中只有一个对象实例 。
数据保存在主内存中的,线程在访问该数据时,并不是直接访问主内存中的数据 , 而是从主内存中拷贝一份数据出来放入工作内存,线程对工作内存中的数据进行操作,操作完成之后再将工作内存中的数据拷贝到主内存中 。
使用关键字来解决因为工作内存-主内存机制导致可能会发生的单例的错误 。
使用关键字修饰的变量,主内存对线程可见 。
线程甲修改了其工作内存中的数据,线程乙工作内存中的数据会同步更新的 。
为什么要用到工作内存?工作内存可以用到CPU的缓存,程序的效率更高 。但是线程不安全的 。
双重锁
package com.m.test;//断点调试:F5,6,7,8,public class Class01 {public static void main(String[] args) {for (int i = 0; i < 5; i++) {new Thread(new Runnable() {@Overridepublic void run() {Singleton singleton = Singleton.getInstance();}}).start();;}}}
public class Singleton {private volatile static Singleton singleton = null;private Singleton() {System.out.println("创建了Singleton对象");}public static Singleton getInstance() {if (singleton == null) {synchronized (Singleton.class) {if (singleton == null) {singleton = new Singleton();}}}return singleton;}}
导致的死锁--01
package com.m.test;//断点调试:F5,6,7,8,public class Class01 {public static void main(String[] args) {DeadLock d1 = new DeadLock();d1.flag = true;DeadLock d2 = new DeadLock();d2.flag = false;new Thread(d1,"杨三").start();new Thread(d2,"杨四").start();}}
public class DeadLock implements Runnable {public boolean flag;private static Object o1 = new Object();private static Object o2 = new Object();@Overridepublic void run() {if (flag) {synchronized (o1) {System.out.println(Thread.currentThread().getName() + "拿到了筷子o1");try {Thread.currentThread().sleep(100);} catch (InterruptedException e) {e.printStackTrace();}synchronized (o2) {System.out.println(Thread.currentThread().getName() + "拿到了筷子o2,可以吃饭了 。");}}}else{synchronized (o2) {System.out.println(Thread.currentThread().getName() + "拿到了筷子o2");try {Thread.currentThread().sleep(100);} catch (InterruptedException e) {e.printStackTrace();}synchronized (o1) {System.out.println(Thread.currentThread().getName() + "拿到了筷子o1,可以吃饭了 。");}}}}}
避免死锁
new Thread(d1,"杨三").start();try {Thread.currentThread().sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}new Thread(d2,"杨四").start();
导致的死锁--02
【多线程-线程内存可见性-线程同步的单例模式】package com.m.test;public class Class01 {static Thread t1 = null, t2 = null;public static void main(String[] args) {final Object o = new Object();final Object o2 = new Object();char[] c1 = "12345".toCharArray();char[] c2 = "abcde".toCharArray();t1 = new Thread(() -> {synchronized (o) {for (int i = 0; i < c1.length; i++) {System.out.print(c1[i]);try {Thread.sleep(1000);} catch (InterruptedException e1) {// TODO Auto-generated catch blocke1.printStackTrace();}try {t2.join();} catch (InterruptedException e) {e.printStackTrace();}}}}, "t1");t2 = new Thread(() -> {synchronized (o2) {for (int i = 0; i < c2.length; i++) {System.out.print(c2[i]);try {t1.join();} catch (InterruptedException e) {e.printStackTrace();}}}}, "t2");t1.start();t2.start();}}