0
点赞
收藏
分享

微信扫一扫

Java 线程同步-同步方法


方式1 : 同步代码块

方式2  :同步方法

方式3 :单例模式-懒加载

方式4 :同步锁

同步代码块

synchronized(同步锁){

           需要同步操作的代码

}

同步锁 :  为了保证每个线程都能正常执行原子操作,java 引入线程同步机制。

同步监听对象/同步锁/同步监听器/互斥锁。

对象的同步锁只是一个概念,可以想象为在对象上标记了一个锁。

java 程序运行使用任何对象作为同步监听对象,但是一般的,我们把当前并发访问的共同资源作为同步监听对象

注意: 在任何时候,最多允许一个线程拥有同步锁.

package com._520it.day01._05_synchronized;
// 使用同步代码块

class Apple1 implements Runnable{
private int num = 50 ;

public void run() {



for(int i = 0 ; i<50; i++) {

// 同步代码块
synchronized(this) {
// 该对象就是共享资源
if(num>0) {
// 模拟网络延迟

System.out.println(Thread.currentThread().getName()+"吃了编号为" +num+"的苹果");
}
try {
Thread.sleep(10);
}
catch(InterruptedException e ) {
e.printStackTrace();
}
num-- ;
}
}
}
}
public class SynchronizedBlockDemo {

public static void main(String[] args) {
Apple1 a = new Apple1() ;
new Thread(a,"小A").start();
new Thread(a,"小B").start();
new Thread(a,"小C").start();

}

}

同步方法 :  使用 synchronized 修饰的方法,就叫同步方法,保证A线程执行该方法时,其他线程只能在方法外等待

synchronized public void doWork(){

}

问题 : 同步锁是谁啊 ? 

   对于非static 方法,同步锁就是this

   对于static 方法, 我们使用当前方法所在的类的字节码对象 (Apple2.class)

注意 : 不要使用 synchronized 修饰 run 方法,修饰之后,某个线程就执行完了所有的功能.就好比多个线程出现串行

解决方案 :  把需要同步操作的代码定义在一个新的方法中,并且该方法使用 synchonized 修饰,再在run 方法中调用新的方法即可。

package com._520it.day01._05_synchronized;
// 使用同步代码块

class Apple1 implements Runnable{
private int num = 50 ;

public void run() {
for (int i = 0 ;i<50 ; i ++ ) {
eat() ;
}
}
synchronized private void eat() {

if(num>0) {
// 模拟网络延迟

System.out.println(Thread.currentThread().getName()+"吃了编号为" +num+"的苹果");
}
try {
Thread.sleep(10);
}
catch(InterruptedException e ) {
e.printStackTrace();
}
num-- ;

}
}
public class SynchronizedBlockDemo {

public static void main(String[] args) {
Apple1 a = new Apple1() ;
new Thread(a,"小A").start();
new Thread(a,"小B").start();
new Thread(a,"小C").start();

}

}

synchroized的好与坏

好处 : 保证了多线程并发访问时的同步操作,避免线程的安全性问题。

缺点 : 代码块性能降低。/ 尽量减少synchroized 代码块

单例模式 : 

单例模式 -饿汉式 

package com._520it.day01._05_synchronized;

// 单例模式-饿汉型
public class ArrayUtill1 {
// 外界不能创建对象了,
private ArrayUtill1() {

}
private static ArrayUtill1 instance = new ArrayUtill1() ;
// 对外的接口
public static ArrayUtill1 getInstance() {
return instance ;
}

}

单例模式-懒汉式

package com._520it.day01._05_synchronized;
// 单例模式 - 懒汉型
public class ArrayUtil2 {

private ArrayUtil2() {

}
private static ArrayUtil2 instance = null ;

// 同步方法 : 此时 线程同步对象是 ArrayUtil2.class
synchronized public static ArrayUtil2 getinstance() {
// 在获取时才创建对象;
if(instance == null ) {
instance = new ArrayUtil2() ;
}
return instance ;
}
}

此时 懒汉型代码是存在线程安全问题的, 我们当然可以直接加 synchronized 修饰整个代码块,但是为了提升性能,我们常常会对有安全隐患的代码段加加修饰。

  "双重检查加锁" : 

  可以使用"双重检查加锁"的方式实现,就可以既可以实现线程安全,又能够使性能不受很大的影响。

  所谓的"双重检查加锁" ,就是 ,并不是每次进入 getinstance 方法都需要同步,而是先不同步,进入方法后,先检查实例是否存在,如果不存在才进行下面的同步块,这是第一重检查,进入同步块后,再次检查实例是否存在,如果不存在,就在同步的情况下创建一个实例,这是第二重检查。

volatile ,他的意思是: 被volatile 修饰的变量的值,将不会被本地线程缓存,所有对该变量

的读写都是直接操作共享内存,从而确保多个线程能正确处理该变量。

注意 :由于 volatile 关键字可能会屏蔽jvm中的一些必要的代码优化,所以运行效率不是很高。

package com._520it.day01._05_synchronized;
// 单例模式 - 懒汉型
public class ArrayUtil2 {

private ArrayUtil2() {

}
private static volatile ArrayUtil2 instance = null ;

// 同步方法 : 此时 线程同步对象是 ArrayUtil2.class
public static ArrayUtil2 getinstance() {
// 在获取时才创建对象;
if (instance == null) {
synchronized (ArrayUtil2.class) {
if(instance == null ) {
instance = new ArrayUtil2() ;
}
}
}
return instance ;
}
}

同步锁 : 


package com._520it.day01._05_synchronized;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class Apple3 implements Runnable {
private int num = 50 ;
private final Lock lock = new ReentrantLock() ;
public void run() {
for (int i = 0 ;i<50 ; i ++ ) {
eat() ;
}
}
//
private void eat() {
if(num>0) {
lock.lock(); // 获取锁

try {
System.out.println(Thread.currentThread().getName()+"吃了编号为" +num+"的苹果");

Thread.sleep(10);
num-- ;
}

catch (Exception e) {
e.printStackTrace();
}finally {

lock.unlock();
}
}

}
}

public class lockDemo {

public static void main(String []args) {
Apple3 a = new Apple3() ;
new Thread(a,"小A").start();
new Thread(a,"小B").start();
new Thread(a,"小C").start();

}

}

 

举报

相关推荐

0 条评论