Thread-线程的同步
Posted xiaokw
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Thread-线程的同步相关的知识,希望对你有一定的参考价值。
线程的同步实现方式
方式一:同步代码块
synchronized(锁对象){
//需要上锁的内容(同步代码块)
}
方式二:同步方法
public synchronized 返回类型 方法名(参数){
//需要上锁的内容(同步代码块)
}
普通的同步方法,锁对象是this
静态的同步方法,锁对象是:当前类.class
要求
- 有多线程
- 多个线程使用的锁对象必须是同一个
- wait、notifiy、notifiyAll和当前同步代码的锁对象必须是同一个,否则报异常
扩展:
synchronized("abc"){} //可以实现线程同步,因为abc在字符串常量池中,但即使没有共享的对象也会需要排队等待
Object obj = new Object(); //可以定一个全局属性,实现有共享对象obj
synchronized(obj){}
案例:解决单例模式中懒汉式多线程问题
public class Singletion_Demo3 {
public static void main(String[] args) {
A a = new A();
A b = new A();
a.start();
b.start();
}
}
class A extends Thread{
public void run() {
for(int i=0;i<10;i++) {
System.out.println(Single.getInstance());
}
}
}
class Single{
private Single() {}
private static Single s;
public static Single getInstance() {
if(s==null) //提高效率
synchronized(Single.class) {
if(s == null) { //线程安全
try {
Thread.sleep(100); //放大问题
} catch (InterruptedException e) {
e.printStackTrace();
}
s = new Single();
}
}
return s;
}
}
并发容器
CopyOnWriteArrayList
底层已经实现了线程同步
以下是不安全的线程
import java.util.ArrayList;
import java.util.List;
public class Thread_Demo1 {
public static void main(String[] args) throws InterruptedException{
List<Integer> listNum = new ArrayList<>();
for(int i=0;i<100;i++) {
new Thread(()->{
for(int j=0;j<100;j++)
// synchronized(listNum) {
listNum.add(j);
// }
}).start();
}
Thread.sleep(5000);
System.out.println(listNum.size());
}
}
可以使用并发容器解决以上线程不安全问题
import java.util.concurrent.CopyOnWriteArrayList;
public class Thread_Demo2 {
public static void main(String[] args) throws InterruptedException{
CopyOnWriteArrayList<Integer> listNum = new CopyOnWriteArrayList<>();
for(int i=0;i<100;i++) {
new Thread(()->{
for(int j=0;j<100;j++)
listNum.add(j);
}).start();
}
Thread.sleep(5000);
System.out.println(listNum.size());
}
}
线程死锁
产生
public class DeathLock {
public static void main(String[] args) {
new DeathMethod(true,"小红").start();
new DeathMethod(false,"小明").start();
}
}
class EatApple{
public void eat() {
System.out.println(Thread.currentThread().getName()+"吃苹果");
}
}
class EatBanana{
public void eat() {
System.out.println(Thread.currentThread().getName()+"吃香蕉");
}
}
class DeathMethod extends Thread{
private static EatApple apple = new EatApple();
private static EatBanana banana = new EatBanana(); ;
boolean flag;
public DeathMethod(boolean flag,String name) {
super(name);
this.flag = flag;
}
public void run() {
if(flag) {
synchronized(apple) {
apple.eat();
synchronized(banana) {
banana.eat();
}
}
}else {
synchronized(banana) {
banana.eat();
synchronized(apple) {
apple.eat();
}
}
}
}
}
就会出现以下情况,线程无法执行下去,一直在等待
小红吃苹果
小明吃香蕉
解决
更改run方法中的锁机制
不要在同一个代码块中,同时持有多个对象的锁
public void run() {
if(flag) {
synchronized(apple) {
apple.eat();
}
synchronized(banana) {
banana.eat();
}
}else {
synchronized(banana) {
banana.eat();
}
synchronized(apple) {
apple.eat();
}
}
}
以上是关于Thread-线程的同步的主要内容,如果未能解决你的问题,请参考以下文章
在控制台应用程序中,为啥在等待的异步任务中使用同步阻塞代码 (Thread.Sleep(..)) 的行为类似于多线程? [复制]