java 多线程研究:锁的概念
java多线程:锁
java的多线程中的锁是干嘛的呢?在网上找了很多博客,大都是很专业的语言,让我一时间摸不着头脑。下面分三个部分来总结多线程中的锁的概念。
一,基础概念:
多线程在运行的时候可能会遇到这样的问题,多个线程要用到同一个资源,那么可能会出现错乱,比如线程要改动资源里的数据,那么多个线程同时改就乱了套了。就像公共厕所,必须要一个一个接着上,不能两个人或者多个人同时上。那么锁这个东西就是像厕所里的门,一个人在上厕所,锁上了们,那下一个人就不能进去了。同样的,如果我们想让某一个程序或者某一个变量只能同时被一个线程运行,就得给程序上锁。所以上了锁,就能保证线程有秩序的去运行了。
这里补充一个面试常问的问题:进程和线程的区别:进程是某一个具有独立功能的程序的运行活动,它可以申请系统资源,是一个活动的实体。二线程的范围要比进程小,一个进程可以拥有多个线程。我们把进程作为分配资源的基本单位,而把线程作为独立运行和独立调用的基本单位。
二,实现方式:
具体来说呢。首先Object对象,都有自己的一把锁,也就是说,你随便定义一个变量,这个变量就有一把锁,保证自己只能同时被一个线程使用。这是对象锁。如果我们想给一个函数上锁怎么办?函数定义加上关键字synchronized就可以了,这个函数就被上锁了。如果我们想让一段代码块上锁呢?
synchronized(object){
#####要加锁的代码块
}
这样代码块就被上锁了,而synchronized()里面的参数的作用就是提供锁,因为odject对象自己有把锁,被synchronized(object)标记的代码块,自然就被object的锁,锁上了。
那么我们如何给一个类上锁呢?我需要在类的静态成员中添加synchronized,因为类的静态成员,是所有实例共享的,所以给静态成员加锁,就相当于给类加锁。其实类锁的作用并不是给类加锁:给类的普通成员函数加锁,同一个实例对象,的确不可以用多个线程访问加锁的成员函数。但是处于两个实例对象中的不同线程访问加锁的成员函数就不受影响了。所以类锁的概念就是让不同的实例对象中线程,访问静态成员函数也受到限制。
所以总结一下,锁的类型有:对象锁,类锁(实际上也是方法所),方法锁,代码块锁。
看一下代码例子:
测试主类:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package javathreadlock;
import java.lang.Thread;
/**
*
* @author chenyongkang
*/
public class JavaThreadlock {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
//两个测试类的实例对象
ThreadLock lock = new ThreadLock();
ThreadLock lock2 = new ThreadLock();
//同一个对象的两个线程
Test1 t1 = new Test1(lock,1);
Test2 t2 = new Test2(lock,2);
t1.start();
t2.start();
//通过测试结果可以看出,t1,t2线程不能同时执行被synchronized标记的代码块或者方法。
//不同对象的不同线程
Test3 t3 = new Test3(lock2,3);
Test4 t4 = new Test4(lock,4);
//t3.start();
//t4.start();
//通过测试结果可以看出,不同对象的不同线程,执行被synchronized标记的代码块或者方法不受影响,
//而执行被synchronized标记的静态函数,则受到限制
}
}
参与测试的线程类:
class Test1 extends Thread{
public ThreadLock lock;
public int i;
public Test1(ThreadLock lock,int i){
this.lock=lock;
this.i=i;
}
public void run(){
lock.nolock(i);
lock.lock5(i);
//ThreadLock.lock4(i);
}
}
class Test2 extends Thread{
public ThreadLock lock;
public int i;
public Test2(ThreadLock lock,int i){
this.lock=lock;
this.i=i;
}
public void run(){
lock.nolock(i);
//lock.lock5(i);
ThreadLock.lock4(i);
}
}
class Test3 extends Thread{
public ThreadLock lock;
public int i;
public Test3(ThreadLock lock,int i){
this.lock=lock;
this.i=i;
}
public void run(){
lock.nolock(i);
//lock.lock1(i);
//lock.lock2(i);
lock.lock5(i);
ThreadLock.lock4(i);
}
}
class Test4 extends Thread{
public ThreadLock lock;
public int i;
public Test4(ThreadLock lock,int i){
this.lock=lock;
this.i=i;
}
public void run(){
lock.nolock(i);
//lock.lock1(i);
//lock.lock2(i);
lock.lock5(i);
ThreadLock.lock4(i);
}
}
加各种锁的资源类:
class ThreadLock{
//统计类锁加锁次数
public static int i;
//类对象
public Object obj = new Object();
//不加锁的代码块
public void nolock(int thread){
try{
System.out.println("线程"+thread+"正在运行");
Thread.sleep(2000);
}
catch(Exception e){
e.printStackTrace();
}
}
//方法锁
public synchronized void lock1(int thread){
try{
System.out.println("方法锁一正在被线程"+thread+"运行");
Thread.sleep(2000);
System.out.println("方法所一被线程"+thread+"执行完了");
}
catch(Exception e){
e.printStackTrace();
}
}
//代码块锁1
public void lock2(int thread){
synchronized(this){
try{
System.out.println("代码块锁方法一正在被线程"+thread+"运行");
Thread.sleep(2000);
System.out.println("代码块锁方法一正在被线程"+thread+"执行完了");
}
catch(Exception e){
e.printStackTrace();
}
}
}
//代码块锁方法2
public void lock3(int thread){
synchronized(obj){
try{
System.out.println("代码块锁方法二正在被线程"+thread+"运行");
Thread.sleep(2000);
System.out.println("代码块锁方法二正在被线程"+thread+"执行完了");
}
catch(Exception e){
e.printStackTrace();
}
}
}
//类锁方法
public synchronized static void lock4(int thread){
try{
System.out.println("类锁方法正在被线程"+thread+"运行");
Thread.sleep(2000);
System.out.println("类锁方法正在被线程"+thread+"执行完了");
}
catch(Exception e){
e.printStackTrace();
}
}
//代码块锁3
public void lock5(int thread){
synchronized(this){
try{
System.out.println("代码块锁方法三正在被线程"+thread+"运行");
Thread.sleep(2000);
System.out.println("代码块锁方法三正在被线程"+thread+"执行完了");
}
catch(Exception e){
e.printStackTrace();
}
}
}
}
我们把Test1,和Test2的run里面改一下。t1和t2分别执行lock1和lock5,互相不影响,因为类锁和锁函数里面的锁不冲突。而分别执行lock2和lock6,是不可以的,因为lock2和lock6中的代码块参数都是this,这两个代码块共用一个this的锁。分别执行lock1和lock6,也不可以,因为this是指当前类对象的锁,普通函数上的锁也是当前类对象的锁。如果分别执行lock1所以被synchronized标记的代码块,关键看锁是哪一个。同一个参数与的不同代码块,相当于被绑在一起。
三,wait 和sleep的区别。
wait函数是Object的类函数,表示该对象的锁暂时挂起,任何线程都不能使用这个对象,正在使用的线程,也必须交出锁,然后和别的要使用该对象的线程等着。如果要恢复状态,就使用notify函数,然后再等待池里,随便选一个等待的线程来继续运行。
而sleep函数是Thread线程的函数,表示当前线程睡眠多少多少时间。
四,死锁的概念
先简单举个例子,介绍一下死锁,比如有两个线程A,B,和两个对象a,b。现在A正在调用a,调用a之后A想调用b。B正在使用b,调用完b,之后想调动a。于是A,B 两个线程分别抱着a,b的锁不放开,互相等对方放开锁,然后自己就可以执行下一步。于是程序就发生了死锁。我举一个栗子:
线程t1使用了fun1之后想使用fun2,t2使用了fun2之后想使用fun1
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package javadeadlock;
/**
*
* @author chenyongkang
*/
public class Javadeadlock {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
ThreadLock lock=new ThreadLock();
Test1 t1=new Test1(lock,1);
Test2 t2=new Test2(lock,2);
t1.start();
t2.start();
}
}
class ThreadLock extends Thread{
private Object obj=new Object();
public synchronized void fun1(int i){
try{
System.out.println("我在使用函数1,我是线程"+i);
Thread.sleep(2000);
System.out.println("我使用完了,我要是使用函数2我是线程"+i);
fun2(i);
}
catch(Exception e){
e.printStackTrace();
}
}
public void fun2(int i){
synchronized(obj){
try{
System.out.println("我在使用函数2,我是线程"+i);
Thread.sleep(2000);
System.out.println("我使用完了,我要使用函数1我是线程"+i);
fun1(i);
}
catch(Exception e){
e.printStackTrace();
}
}
}
}
class Test1 extends Thread{
ThreadLock lock;
int i;
public Test1(ThreadLock lock,int i){
this.lock=lock;
this.i=i;
}
public void run(){
try{
lock.fun1(i);
}catch(Exception e){
e.printStackTrace();
}
}
}
class Test2 extends Thread{
ThreadLock lock;
int i;
public Test2(ThreadLock lock,int i){
this.lock=lock;
this.i=i;
}
public void run(){
try{
lock.fun2(i);
}catch(Exception e){
e.printStackTrace();
}
}
}
结果:卡在那里。
java 多线程研究:锁的概念的更多相关文章
- Java 多线程:锁(一)
Java 多线程:锁(一) 作者:Grey 原文地址: 博客园:Java 多线程:锁(一) CSDN:Java 多线程:锁(一) CAS 比较与交换的意思 举个例子,内存有个值是 3,如果用 Java ...
- Java 多线程:锁(二)
Java 多线程:锁(二) 作者:Grey 原文地址: 博客园:Java 多线程:锁(二) CSDN:Java 多线程:锁(二) AtomicLong VS LongAddr VS Synchroni ...
- Java 多线程:锁(三)
Java 多线程:锁(三) 作者:Grey 原文地址: 博客园:Java 多线程:锁(三) CSDN:Java 多线程:锁(三) StampedLock StampedLock其实是对读写锁的一种改进 ...
- JAVA多线程与锁机制
JAVA多线程与锁机制 1 关于Synchronized和lock synchronized是Java的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码 ...
- java多线程编程01---------基本概念
一. java多线程编程基本概念--------基本概念 java多线程可以说是java基础中相对较难的部分,尤其是对于小白,次一系列文章的将会对多线程编程及其原理进行介绍,希望对正在多线程中碰壁的小 ...
- Java多线程系列——锁的那些事
引入 Java提供了种类丰富的锁,每种锁因其特性的不同,在适当的场景下能够展现出非常高的效率. 下面先带大家来总体预览一下锁的分类图 java锁的具体实现类 1.乐观锁 VS 悲观锁 乐观锁与悲观锁是 ...
- (转)java 多线程 对象锁&类锁
转自:http://blog.csdn.net/u013142781/article/details/51697672 最近工作有用到一些多线程的东西,之前吧,有用到synchronized同步块,不 ...
- java多线程----悲观锁与乐观锁
java多线程中悲观锁与乐观锁思想 一.悲观锁 总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁(共享资源每次只给一个线 ...
- java多线程之锁 -- 偏向锁、轻量级锁、自旋锁、重量级锁
转载至:https://blog.csdn.net/zqz_zqz/article/details/70233767 之前做过一个测试,详情见这篇文章<多线程 +1操作的几种实现方式,及效率对比 ...
随机推荐
- Dubbo调用链(version:2.5.3)
Consumer 调用 Provider的过程: (CONSUMER)Dubbo服务调用处 --> 调用RPC代理 --> InvokerInvocationHandler#invoke( ...
- 手机APP支付--整合银联支付控件
长话短说,本文根据银联官方说明文档,简单总结下,并且说明下中途碰到问题该如何解决. 一.开发前的准备工作1. 打开https://open.unionpay.com/,后续说的文档下载.FAQ查询等都 ...
- c 各种编译器(gcc clang)
很多时候,出现一些类似GNU,GCC,CLANG,LLVM等与编译器有关的名词的时候,都不太清楚它到底是干嘛的,理解这些东西后, 对于xcode中很多配置型的需求修改起来都会得心应手,因此有必要了解透 ...
- 从Gallery中获取图片示例
一.MainActivity类 package com.example.gallerydemo; import android.net.Uri; import android.os.Bundle; i ...
- GreenPlum数据库安装
第一章 文档概述 本文描述适用于Greenplum4.0以上版本的安装操作.所涉及到的操作系统相关参数调整,主要针对Redhat Linux操作系统. 第二章 安装介质 操作系统:Cent ...
- SQL筛选出同一学科的时间最新的记录
1.建表语句 CREATE TABLE `score` ( `id` ) NOT NULL AUTO_INCREMENT, `student_id` ) ' COMMENT '学生表ID', `nam ...
- Selenium 切换 Frame
我们知道网页中有一种节点叫作 iframe ,也就是子 Frame ,相当于页面的子页面,它的结构和外部网页的结构完全一致. Selenium 打开页面后,它默认是在父级 Frame 里面操作,而此时 ...
- oracle 排序字段自增长
<insert id="insertGoodsDescription" parameterClass="goodsDescription" > &l ...
- 偶值得纪念的一天-初学习C#
今天好悲催啊,竟然生病啦,不过一切还好! 今天我们在云和数据学习的第二天,上午没有听课,似乎学习了变量的定义以及命名方法,还有变量类型的显隐式转换:我感觉这些还是在之前看书知道啦把,因此看啦看老师做的 ...
- codeforcess水题100道
之所以在codeforces上找这100道水题的原因是为了巩固我对最近学的编程语言的掌握程度. 找的方式在codeforces上的PROBLEMSET中过的题最多的那些题里面出现的最前面的10个题型, ...