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. mysql中,创建表的时候指定if not exists参数的作用?

    需求说明: 在创建表的时候,如果指定if not exists语句,有什么作用,在此做个实验,并且官方手册, 理解下这个参数的作用. 操作过程: 1.创建测试表test01 mysql> cre ...

  2. java stream Api

    Stream的简单使用 Stream的使用分为两种类型: Intermediate,一个Stream可以调用0到多个Intermediate类型操作,每次调用会对Stream做一定的处理,返回一个新的 ...

  3. Linux命令缩写的全称

    [目录|文件] ls : list(列出目录内容) pwd : print work directory(打印当前目录,现示当前工作目录的绝对路径) cd : change directory(改变目 ...

  4. Uva--11324--The Largest Clique【有向图强连通分量】

    链接:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&am ...

  5. Mybatis -- 批量更新 -- updateBatch

    mysql数据库配置: 数据库连接必须配置:&allowMultiQueries=true并且‘&’ 用&替换 jdbc.url=jdbc:mysql://192.168.10 ...

  6. iOS NSError

    写在前面 在iOS开发中,NSError的使用非常常见,使用也比较简单,也正因为简单,所以对这一部分知识不甚注重.但是近期在做app底层网络封装时发现了一些问题.我使用的网络框架是AFNetworki ...

  7. C语言中如何计算时间差

    #include <time.h>   #include <stdio.h>   int main()   {       time_t start ,end ;        ...

  8. C++ template —— 深入模板基础(二)

    上一篇C++ template —— 模板基础(一)讲解了有关C++模板的大多数概念,日常C++程序设计中所遇到的很多问题,都可以从这部分教程得到解答.本篇中我们深入语言特性.------------ ...

  9. Oralce分析函数

    1 列传行  listagg(city,',')  within GROUP (order by city)    over (partition by nation) rank with temp ...

  10. 关于Android开发中使用的XML

    1.布局 FrameLayout: 以堆叠方式显示一个或多个子视图. GridLayout: 将子视图按行和列排列. LinearLayout: 将所有子视图排列成一行或一列. RelativeLay ...