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 多线程研究:锁的概念的更多相关文章

  1. Java 多线程:锁(一)

    Java 多线程:锁(一) 作者:Grey 原文地址: 博客园:Java 多线程:锁(一) CSDN:Java 多线程:锁(一) CAS 比较与交换的意思 举个例子,内存有个值是 3,如果用 Java ...

  2. Java 多线程:锁(二)

    Java 多线程:锁(二) 作者:Grey 原文地址: 博客园:Java 多线程:锁(二) CSDN:Java 多线程:锁(二) AtomicLong VS LongAddr VS Synchroni ...

  3. Java 多线程:锁(三)

    Java 多线程:锁(三) 作者:Grey 原文地址: 博客园:Java 多线程:锁(三) CSDN:Java 多线程:锁(三) StampedLock StampedLock其实是对读写锁的一种改进 ...

  4. JAVA多线程与锁机制

    JAVA多线程与锁机制 1 关于Synchronized和lock synchronized是Java的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码 ...

  5. java多线程编程01---------基本概念

    一. java多线程编程基本概念--------基本概念 java多线程可以说是java基础中相对较难的部分,尤其是对于小白,次一系列文章的将会对多线程编程及其原理进行介绍,希望对正在多线程中碰壁的小 ...

  6. Java多线程系列——锁的那些事

    引入 Java提供了种类丰富的锁,每种锁因其特性的不同,在适当的场景下能够展现出非常高的效率. 下面先带大家来总体预览一下锁的分类图 java锁的具体实现类 1.乐观锁 VS 悲观锁 乐观锁与悲观锁是 ...

  7. (转)java 多线程 对象锁&类锁

    转自:http://blog.csdn.net/u013142781/article/details/51697672 最近工作有用到一些多线程的东西,之前吧,有用到synchronized同步块,不 ...

  8. java多线程----悲观锁与乐观锁

    java多线程中悲观锁与乐观锁思想 一.悲观锁 总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁(共享资源每次只给一个线 ...

  9. java多线程之锁 -- 偏向锁、轻量级锁、自旋锁、重量级锁

    转载至:https://blog.csdn.net/zqz_zqz/article/details/70233767 之前做过一个测试,详情见这篇文章<多线程 +1操作的几种实现方式,及效率对比 ...

随机推荐

  1. 第五种方式,python使用组合来添加类方法和属性(二),以selenium的webdriver为例

    组合优点多,但经常比继承需要额外的代码. 上一篇是 介绍装饰器.继承.元类.mixin,四种給类动态添加类属性和方法的四种方式. 此篇介绍直接把被组合的类的属性直接加入到类里面,前面的四个例子很简单, ...

  2. javascript的闭包计数器实现,python实现各种方法来实现计数器

    菜鸟教程的javascript闭包章节中,演示了js计数器的实现.    教程地址 http://www.runoob.com/js/js-function-closures.html 代码1 var ...

  3. ubuntu alsa

    今天要在linux下搞音频编程,在网上查阅了一下资料,网上很多资料都是在linux下直接对/dev/dsp进行编程的,因为在以往的linux系统中,我们是可以通过cat  xxx.wav /dev/d ...

  4. 安装office2010出现了错误,提示要安装MSXML6.10.1129.0解决方法

    将下面的内容复制到记事本中,然后将记事本存成.reg文件 Windows Registry Editor Version 5.00[HKEY_CLASSES_ROOT\TypeLib\{F5078F1 ...

  5. Aspose------导出Excel

    代码: /// <summary> /// 导出Excel /// </summary> /// <typeparam name="T">泛型类 ...

  6. ios开发之--首页 导航栏隐藏 下一级页面显示,pop回来显示白条

    解决方法,在首页中实现如下两个方法,代码如下: -(void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated] ...

  7. iOS protocbuf安装使用

    protobuf文件地址:https://github.com/google/protobuf 1.问题/usr/local.bak/lib /usr/local.bak/man /usr/local ...

  8. oracle nvl,having的用法

    select oi.order_id,opl.payment_no,opl.back_no, oi.commit_time, oi.receive_mobile, oi.receive_user, n ...

  9. React Native(十一)——删除事件以及刷新列表

    需求:删除列表中的某一项,但不刷新整个页面,底下的数据顺势而上(第一张是原始数据,第二张是删除掉"你会介今年"这条动态后显示的数据). 中间的过程比较曲折,只因为刚开始的时候自己只 ...

  10. EGit 在使用时出现 git-upload-pack not found 的错误

    在 Ubuntu 上使用Eclipse 的插件 EGit 从 GitHub 上下载资源时出现 git-upload-pack not found 的错误,如图 (另,EGit 在 Windows 上的 ...