Java04 线程同步问题解决——线程锁(同步锁、互斥锁)

目录

[TOC]

写在最前:

可能有误,请大家批评指正

一、线程切换

Java中,如果要实现在一个线程间的线程切换,需要在线程中使用Thread.yield()即可让出CPU时间。

二、线程锁(也叫同步锁、互斥锁)

线程锁可以在有效缩小同步范围的同时,尽可能的保证并发效率

2.1 使用synchronized关键字对方法进行加锁

对整个线程处理加锁(严重影响效率,不常用

2.1.1 语法

public synchronized void test(){

}

2.1.2 案例

package com.javase.thread;

import javax.management.RuntimeErrorException;

/**
 *      这个类主要讲了Sychronized关键字,给方法加了Synchronized关键字以后,线程在调用这个方法时,相当于对这个方法加了锁,
 * 那么其他线程就不能调用这个方法了(处于阻塞状态)
 *
 * @author gupan
 *
 */
public class ThreadSyncSychronized {
    public static void main(String[] args) {
        final Table2 table = new Table2();
        Thread t1 = new Thread() {
            public void run() {
                while (true) {
                    try {
                        int bean = table.getBean();
                        Thread.yield(); // 线程切换语句,让出CPU时间
                        System.out.println(getName() + ","  + table.getBean());
                    } catch (RuntimeErrorException e) {
                        System.out.println(getName() + ","  + e);
                        break;
                    }

                }
            }
        };

        Thread t2 = new Thread() {
            public void run() {
                while (true) {
                    try {
                        int bean = table.getBean();
                        Thread.yield(); // 线程切换语句,让出CPU时间
                        System.out.println(getName() + ","  + table.getBean());
                    } catch (RuntimeErrorException e) {
                        System.out.println(getName() + "," + e);
                        break;
                    }
                }
            }
        };
        t2.start();
        t1.start();
    }
}

class Table2{
    // 桌子上有20元钱
    private int beans = 20;

    public synchronized int getBean() throws RuntimeErrorException{
        if (this.beans == 1) {
            throw new RuntimeErrorException(null, "地主家没有余粮了");
        }
        Thread.yield(); // 线程切换语句,让出CPU时间
        return this.beans--;
    }
}

2.2 使用synchronize关键字对线程方法中的某一部分加锁(同步块的方式)

2.2.1 语法

// 注意这里是this,可以写new Object(),但是这样起不到加锁的效果
// 也就是说,要实现加锁的效果,需要保证是对同一个对象(也就是保证synchronized后面所跟对象是同一个)加锁
synchronized(this){
    ···
    // 加锁语句
}

2.2.2 案例

package com.javase.thread;
/**
 * 这个类主要演示小范围的使用锁。尽可能的提高并发效率
 *
 * synchronized(this){
 *      ···
 *      // 加锁语句
 * }
 *
 * @author Think
 *
 */
public class ThreadSyncLock {
    public static void main(String[] args) {
        final Shop shop = new Shop();
        Thread t1 = new Thread() {
            public void run() {
                shop.buy();
            }
        };

        Thread t2 = new Thread() {
            public void run() {
                shop.buy();
            }
        };

        t1.start();
        t2.start();
    }
}

class Shop{
    public void buy() {
        Thread t = Thread.currentThread();
        try {
            System.out.println(t.getName() + "正在挑衣服");
            Thread.sleep(1000);

            // 需要传入当前方法所属对象,所以这里要传入this
            synchronized (this) {
                System.out.println(t.getName() + "正在试衣服");
                Thread.sleep(1000);
            }

            System.out.println(t.getName() + "结账离开");
            Thread.sleep(1000);
        }catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
    }
}

2.3 静态方法加锁

如果对静态方法加了synchronized关键字,由于静态方法只有一份,整个方法一定是加了互斥锁

package com.javase.thread;

import com.javase.string.Object;

/**
 * 静态方法的同步
 *      当一个静态方法被synchronized修饰以后,那么该方法就是同步方法,由于静态方法从属类,
 * 全局就一份,所以同步的静态方法一定具有同步效果,与对象无关
 *
 * @author gupan
 *
 */
public class ThreadSyncStatic {
    public static void main(String[] args) {
        Thread t1 = new Thread() {
            public void run() {
                Foo.dosome();
            }
        };
        Thread t2 = new Thread() {
            public void run() {
                Foo.dosome();
            }
        };
        t1.start();
        t2.start();
    }
}

class Foo{
    public static synchronized void dosome() {
        try {
            Thread t = Thread.currentThread();
            System.out.println(t.getName() + "正在等待运行dosome方法");
            Thread.sleep(1000);

            System.out.println(t.getName() + "正在运行dosome方法");
            Thread.sleep(1000);

            System.out.println(t.getName() + "执行dosome方法完毕");
        }catch (Exception e) {
            // TODO: handle exception
        }
    }
}

运行结果:

Thread-1正在等待运行dosome方法
Thread-1正在运行dosome方法
Thread-1执行dosome方法完毕
Thread-0正在等待运行dosome方法
Thread-0正在运行dosome方法
Thread-0执行dosome方法完毕

2.3 互斥锁

2.3.1 同步锁和互斥锁

同步锁和互斥锁原理相同,存在的是用法上的小差异。当两个线程调用同一段代码,并且,对于两个线程的同步监视器,看到的代码相同,那就是同步锁;但是,对于几段代码,用一个同步监视器进行访问,几段代码不能同时执行,就是互斥锁

package com.javase.thread;
/**
 * 这段代码主要演示互斥锁的使用
 *      使用synchronized修饰这段代码之后,只要他们同步监视器对象相同,那么这几段代码见就是互斥关系,多个线程不能同时执行这些代码
 *
 * @author gupan
 *
 */
public class ThreadSyncMatual {
    /**
     * 线程t1和t2不能同时调用methodA或methodB方法,实现互斥关系
     *
     * @param args
     */
    public static void main(String[] args) {
        Boo boo = new Boo();
        Thread t1 = new Thread() {
            public void run() {
                boo.methodA();
            }
        };

        Thread t2 = new Thread() {
            public void run() {
                boo.methodB();
            }
        };

        t1.start();
        t2.start();
    }
}

class Boo{
    public void methodA(){
        try{
            Thread t = Thread.currentThread();
            System.out.println(t.getName() + "正在执行A方法");
            Thread.sleep(1000);
            System.out.println(t.getName() + "执行A方法完毕");
        }catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
    }

    public void methodB(){
        try{
            Thread t = Thread.currentThread();
            System.out.println(t.getName() + "正在执行B方法");
            Thread.sleep(1000);
            System.out.println(t.getName() + "执行B方法完毕");
        }catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
    }
}

原文地址:https://www.cnblogs.com/gupan/p/9126082.html

时间: 2024-10-11 07:50:50

Java04 线程同步问题解决——线程锁(同步锁、互斥锁)的相关文章

Java多线程系列--“JUC锁”02之 互斥锁ReentrantLock

ReentrantLock介绍 ReentrantLock是一个可重入的互斥锁,又被称为"独占锁". 顾名思义,ReentrantLock锁在同一个时间点只能被一个线程锁持有:而可重入的意思是,ReentrantLock锁,可以被单个线程多次获取.ReentrantLock分为"公平锁"和"非公平锁".它们的区别体现在获取锁的机制上是否公平."锁"是为了保护竞争资源,防止多个线程同时操作线程而出错,ReentrantLock在

GIL锁与自定义互斥锁

Gil锁保证内存管理数据安全,不能保证所有数据的安全,不同的数据要加不同的锁 from threading import Thread,Lock import time mutex=Lock() n=100 def task(): global n temp=n time.sleep(0.1) n=temp-1 if __name__ == '__main__': l=[] for i in range(100): t=Thread(target=task) l.append(t) t.star

[Todo] 乐观悲观锁,自旋互斥锁等等

乐观锁.悲观锁.要实践 http://chenzhou123520.iteye.com/blog/1860954 http://chenzhou123520.iteye.com/blog/1863407 http://outofmemory.cn/sql/optimistic-lock-and-pessimistic-lock 自旋锁 http://www.cnblogs.com/hdflzh/p/3716156.html http://blog.csdn.net/pi9nc/article/d

线程同步(互斥锁与信号量的作用与区别)

“信号量用在多线程多任务同步的,一个线程完成了某一个动作就通过信号量告诉别的线程,别的线程再进行某些动作(大家都在semtake的时候,就阻塞在 哪里).而互斥锁是用在多线程多任务互斥的,一个线程占用了某一个资源,那么别的线程就无法访问,直到这个线程unlock,其他的线程才开始可以利用这 个资源.比如对全局变量的访问,有时要加锁,操作完了,在解锁.有的时候锁和信号量会同时使用的” 也就是说,信号量不一定是锁定某一个资源,而是流程上的概念,比如:有A,B两个线程,B线程要等A线程完成某一任务以后

python多线程编程(2): 使用互斥锁同步线程

上一节的例子中,每个线程互相独立,相互之间没有任何关系.现在假设这样一个例子:有一个全局的计数num,每个线程获取这个全局的计数,根据num进行一些处理,然后将num加1.很容易写出这样的代码: # encoding: UTF-8import threadingimport time class MyThread(threading.Thread): def run(self): global num time.sleep(1) num = num+1 msg = self.name+' set

Windows线程同步【3】互斥锁(Mutex)

我们前面讲过的临界区,如同一个小房间,张三进去了,李四就不能进,如果李四要进,必须等张三出来. 今天我们要讲的互斥锁,像一个物件,这个物件只能同时被一个线程持有.如此一来,便可以通过互斥锁来实现线程的同步. 一.创建 创建互斥锁的方法是调用函数CreateMutex: CreateMutex(&sa, bInitialOwner, szName); 第一个参数是一个指向SECURITY_ATTRIBUTES结构体的指针,一般的情况下,可以是nullptr. 第二个参数类型为BOOL,表示互斥锁创

linux 线程的同步 二 (互斥锁和条件变量)

互斥锁和条件变量 为了允许在线程或进程之间共享数据,同步时必须的,互斥锁和条件变量是同步的基本组成部分. 1.互斥锁 互斥锁是用来保护临界区资源,实际上保护的是临界区中被操纵的数据,互斥锁通常用于保护由多个线程或多进程分享的共享数据.一般是一些可供线程间使用的全局变量,来达到线程同步的目的,即保证任何时刻只有一个线程或进程在执行其中的代码.一般加锁的轮廓如下: pthread_mutex_lock() 临界区 pthread_mutex_unlock() 互斥锁API pthread_mutex

线程同步机制之互斥锁

进程间通讯介绍 1.几种进程间的通信方式 # 管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用.进程的亲缘关系通常是指父子进程关系. # 有名管道 (named pipe) : 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信. # 信号量( semophore ) : 信号量是一个计数器,可以用来控制多个进程对共享资源的访问.它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源.因此,主要作为进程间以及同一进

python第三十七天,GIL全局解释器锁*****,线程池与进程池 同步异步,阻塞与非阻塞,异步回调

GIL全局解释器锁 1.什么是GIL 官方解释:'''In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple native threads from executing Python bytecodes at once. This lock is necessary mainly because CPython’s memory management is not thread-safe