Java基础之线程锁相关知识总结

一、 synchronized关键字

1.对象锁
a.当使用对象锁的时候,注意要是相同的对象,并且当有线程正在访问对象锁内部的代码的时候,其他线程无法访问。(注意无法访问的范围)。
b.但是并不影响没有使用对象锁的部分的代码的运行。

对象锁分为两类一个叫做synchronized代码块(圆括号内是普通类的对象),另外一个是sybchronized修饰普通成员方法。它们二者其实可以通过this关键字进项转化。

2.类锁
a. 当使用类锁的时候,只要是同一个类的对象.当有线程正在访问类锁内部的代码的时候,其他线程无法访问。(注意无法访问的范围)
b. 但是并不影响没有使用类锁的部分的代码的运

对象锁分为两类一个叫做synchronized代码块(圆括号内是class对象),另外一个是sybchronized修饰静态成员方法。它们二者其实可以通过class对象进项转化。

注意: 类锁和对象锁之间没有关系.

1、不使用线程锁

如果没有加synchronized关键字,会产生线程交错运行

/**
 * 该类写了一个test方法,先不加synchronized关键字
 */
public class A {

	void test() {
		for(int i=0;i<10;i++) {
			System.out.println("线程:"+i);
		}
	}
}

/**
 * 该类继承Thread,重写run方法调用A中的test方法
 */
public class MyThread1 extends Thread{

	A a;

	public void run() {
		a.test();
	}
}

/**
 * 该类继承Thread,重写run方法调用A中的test方法
 */
public class MyThread2 extends Thread{

	A a;

	public void run() {
		a.test();
	}
}

/**
 * 测试程序
 * /
public class Entrance {

	public static void main(String[] args) {

		/**
		 * 演示没有锁时会产生交错现象
		 */
		A a = new A();

		MyThread1 t1 = new MyThread1();
		MyThread2 t2 = new MyThread2();

		t1.a = a;
		t2.a = a;

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

}

产生如下运行结果:
线程:0
线程:1
线程:2
线程:3
线程:4
线程:0
线程:5
线程:6
线程:7
线程:8
线程:9
线程:1
线程:2
线程:3
线程:4
线程:5
线程:6
线程:7
线程:8
线程:9

2、使用对象锁

将A类中test方法代码改成如下代码,其他不变,运行测试类可以产生如下结果

/**
 * 该类写了一个test方法,使用对象锁
 * 分别在锁前锁后增加代码,演示对没有使用对象锁的代码不会产生任何影响
 * 且如果对象锁被锁住,对象锁后面的代码是不会运行的
 */
public class A {

	void test() {
		System.out.println("线程开始");
		synchronized(this) {
			for(int i=0;i<10;i++) {
				System.out.println("线程:"+i);
			}
		}
		System.out.println("线程结束");
	}
}
运行测试类会产生如下结果:(注意:”线程开始“不是在对象锁中的内容)

线程开始
线程:0
线程:1
线程开始
线程:2
线程:3
线程:4
线程:5
线程:6
线程:7
线程:8
线程:9
线程:0
线程:1
线程:2
线程:3
线程:4
线程:5
线程:6
线程结束
线程:7
线程:8
线程:9
线程结束

使用synchronized直接修饰方法等价于synchronized(this)修饰方法内的全部代码

/**
 * synchronized直接修饰方法等价于synchronized(this)修饰方法内的全部代码
 * test和test1方法是等价的
 */
public class A {

	synchronized void test() {
		System.out.println("线程开始");

		for(int i=0;i<10;i++) {
			System.out.println("线程:"+i);
		}

		System.out.println("线程结束");
	}

	void test1() {
		synchronized (this) {
			System.out.println("线程开始");

			for(int i=0;i<10;i++) {
				System.out.println("线程:"+i);
			}

			System.out.println("线程结束");
		}
	}
}
其他代码是一样的,在MyThread1和MyThread2中无论调用test还是test1,结果是一样的,如下:

线程开始
线程:0
线程:1
线程:2
线程:3
线程:4
线程:5
线程:6
线程:7
线程:8
线程:9
线程结束
线程开始
线程:0
线程:1
线程:2
线程:3
线程:4
线程:5
线程:6
线程:7
线程:8
线程:9
线程结束

对象锁对不同的方法也是有用的(类锁也是如此)

/**
 * 类锁对不同的方法也是有用的
 */
public class A {

//	synchronized void test() {
//		for(int i=0;i<10;i++) {
//			System.out.println("方法test:"+i);
//		}
//	}
	void test() {
		synchronized(this) {
			for(int i=0;i<10;i++) {
				System.out.println("方法test:"+i);
			}
		}
	}

//	synchronized void test1() {
//		for(int i=0;i<10;i++) {
//			System.out.println("方法test1:"+i);
//		}
//	}
	void test1() {
		synchronized(this) {
			for(int i=0;i<10;i++) {
				System.out.println("方法test1:"+i);
			}
		}
	}
}
MyThread1中调用test方法,MyThread2中调用test1方法,运行结果如下:

方法test:0
方法test:1
方法test:2
方法test:3
方法test:4
方法test:5
方法test:6
方法test:7
方法test:8
方法test:9
方法test1:0
方法test1:1
方法test1:2
方法test1:3
方法test1:4
方法test1:5
方法test1:6
方法test1:7
方法test1:8
方法test1:9

3、使用类锁

演示当A类中的test方法使用对象锁时,不同对象调用test方法时对象锁是起不到任何作用的

/**
 * 该类写了一个test方法,使用对象锁演示不用对象调用test方法
 */
public class A {

	void test() {
		synchronized(this) {
			for(int i=0;i<10;i++) {
				System.out.println("线程:"+i);
			}
		}
	}
}

MyThread1和MyThread2是一样的,主要在测试程序的不同

测试程序:
public class Entrance {

	public static void main(String[] args) {

		/**
		 * 演示使用不同的对象调用test方法时,对象锁会产生交错现象
		 * 而使用类锁则不会产生这种现象
		 */
		A a1 = new A();
		A a2 = new A();

		MyThread1 t1 = new MyThread1();
		MyThread2 t2 = new MyThread2();

		t1.a = a1;
		t2.a = a2;

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

}

运行结果:

线程:0
线程:1
线程:2
线程:3
线程:4
线程:0
线程:5
线程:6
线程:7
线程:8
线程:9
线程:1
线程:2
线程:3
线程:4
线程:5
线程:6
线程:7
线程:8
线程:9

使用类锁会改变这种情况,无论是那个对象,只要调用的是同一个方法就会产生锁

/**
 * 该类写了一个test方法,使用对象锁演示不用对象调用test方法
 * 将类A中的this改为A.class,其他代码都不变
 */
public class A {

	void test() {
		synchronized(A.class) {
			for(int i=0;i<10;i++) {
				System.out.println("线程:"+i);
			}
		}
	}
}

运行结果:
线程:0
线程:1
线程:2
线程:3
线程:4
线程:5
线程:6
线程:7
线程:8
线程:9
线程:0
线程:1
线程:2
线程:3
线程:4
线程:5
线程:6
线程:7
线程:8
线程:9

对象锁分为两类一个叫做synchronized代码块(圆括号内是普通类的对象),另外一个是sybchronized修饰普通成员方法。它们二者其实可以通过this关键字进项转化。

/**
 * 该类写了一个test方法,使用对象锁演示不用对象调用test方法
 * 将类A中的this改为A.class,其他代码都不变
 */
public class A {

	void test() {
		synchronized(A.class) {
			for(int i=0;i<10;i++) {
				System.out.println("线程:"+i);
			}
		}
	}
}

运行结果:
线程:0
线程:1
线程:2
线程:3
线程:4
线程:5
线程:6
线程:7
线程:8
线程:9
线程:0
线程:1
线程:2
线程:3
线程:4
线程:5
线程:6
线程:7
线程:8
线程:9

类锁这对象锁之间是没有任何关系,互不影响互不干涉

/**
 * 该类写了test方法使用对象锁,写了test1方法使用类锁
 */
public class A {

	synchronized void test() {
			for(int i=0;i<10;i++) {
				System.out.println("方法test:"+i);
			}
	}
	synchronized static void test1() {
		for(int i=0;i<10;i++) {
			System.out.println("方法test1:"+i);
		}
	}
}

MyThread1调用test方法,使用对象锁,MyThread2调用test1方法,使用类锁

测试程序
public class Entrance {

	public static void main(String[] args) {

		A a1 = new A();
		A a2 = new A();

		MyThread1 t1 = new MyThread1();
		MyThread2 t2 = new MyThread2();

		/*
		 	使用同一个对象调用test和test1会产生交错现象
		 	使用不同对象调用test和test1也会产生交错现象
		 */
//		t1.a = a1;
//		t2.a = a1;

		t1.a = a1;
		t2.a = a2;

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

}

运行结果:

方法test:0
方法test:1
方法test1:0
方法test1:1
方法test1:2
方法test1:3
方法test1:4
方法test1:5
方法test1:6
方法test1:7
方法test1:8
方法test1:9
方法test:2
方法test:3
方法test:4
方法test:5
方法test:6
方法test:7
方法test:8
方法test:9

到此这篇关于Java基础之线程锁相关知识总结的文章就介绍到这了,更多相关Java线程锁内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java多线程锁机制相关原理实例解析

    上下文:程序运行需要的环境(外部变量) 上下文切换:将之前的程序需要的外部变量复制保存,然后切换到新的程序运行环境 系统调用:(用户态陷入操作系统,通过操作系统执行内核态指令,执行完回到用户态)用户态--内核态--用户态:两次上下文切换 线程wait()方法:将自身加入等待队列,发生了一次上下文切换 notify()方法:将线程唤醒,也发生了上下文切换 Java线程中的锁:偏向锁.轻量级锁.重量级锁. 注意:偏向锁和轻量级锁都没有发生竞争,重量级锁发生了竞争. 偏向锁:可重入和经常使用某一个线程

  • 深入解析Java并发程序中线程的同步与线程锁的使用

    synchronized关键字 synchronized,我们谓之锁,主要用来给方法.代码块加锁.当某个方法或者代码块使用synchronized时,那么在同一时刻至多仅有有一个线程在执行该段代码.当有多个线程访问同一对象的加锁方法/代码块时,同一时间只有一个线程在执行,其余线程必须要等待当前线程执行完之后才能执行该代码段.但是,其余线程是可以访问该对象中的非加锁代码块的. synchronized主要包括两种方法:synchronized 方法.synchronized 块. synchron

  • Java多线程编程中线程锁与读写锁的使用示例

    线程锁Lock Lock  相当于 当前对象的 Synchronized import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /* * Lock lock = new ReentrantLock(); * lock.lock(); lock.unLock(); * 类似于 synchronized,但不能与synchronized 混用 */ public class L

  • 详解Java同步—线程锁和条件对象

    线程锁和条件对象 在大多数多线程应用中,都是两个及以上线程需要共享对同一数据的存取,所以有可能出现两个线程同时访问同一个资源的情况,这种情况叫做:竞争条件. 在Java中为了解决并发的数据访问问题,一般使用锁这个概念来解决. 有几种机制防止代码收到并发访问的干扰: 1.synchronized关键字(自动创建一个锁及相关的条件) 2.ReentrantLock类+Java.util.concurrent包中的lock接口(在Java5.0的时候引入) ReentrantLock的使用 publi

  • java 线程锁详细介绍及实例代码

    java 线程锁 在Java线程中运用synchronized关键字来达到同步的 synchronized可以锁方法,锁类,锁对象,锁代码块 方法锁 // 加在方法上面的同步锁是this public synchronized void print() { System.out.println("同步方法"); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } } 类锁

  • Java基础之线程锁相关知识总结

    一. synchronized关键字 1.对象锁 a.当使用对象锁的时候,注意要是相同的对象,并且当有线程正在访问对象锁内部的代码的时候,其他线程无法访问.(注意无法访问的范围). b.但是并不影响没有使用对象锁的部分的代码的运行. 对象锁分为两类一个叫做synchronized代码块(圆括号内是普通类的对象),另外一个是sybchronized修饰普通成员方法.它们二者其实可以通过this关键字进项转化. 2.类锁 a. 当使用类锁的时候,只要是同一个类的对象.当有线程正在访问类锁内部的代码的

  • Java基础之反射技术相关知识总结

    一.反射概念 Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法.这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制.反射被视为动态语言的关键. 二.反射应用场景 1.几乎所有的框架都会用到反射 2.程序解耦合使用 3.代码更加的优雅 三.反射更多细节 1.Jdk中的位置: java.lang.reflect包下 2.获取字节码方式 //

  • Java基础学习之运算符相关知识总结

    1.算术运算符 +表示加法运算符 -表示减法运算符 *表示乘法运算符 /表示除法运算符 %表示取模/取余运算符 package com.lagou.Day03; /** * 算术运算符 */ public class Demo01 { public static void main(String[] args) { //1.声明两个int类型的变量并初始化 //int ia = 6;ib = 2;//表示声明两个int类型的变量ia和ib,不推荐使用 int ia = 6; int ib = 2

  • Java基础之内部类与代理知识总结

    目录 一.内部类 1.1 创建内部类 1.2 内部类调用外部类的变量 二.局部内部类 2.1 外部方法访问变量 三.匿名内部类 四.lambda表达式结合局部内部类 五.静态内部类 六.代理 一.内部类 内部类是指在另一个类中的类 内部类可以对同一个包中的所有类隐藏(权限改为private) 内部类方法可以访问定义这个类的作用域中的数据,包括原本私有的数据 注意:内部类位于类的内部,并不意味着类的实例都必须要有内部类的实例 内部类是可以访问定义这个类的属性的,因为内部类的对象总有一个隐式引用,指

  • Java基础之数组超详细知识总结

    一.一维数组 1.Java语言中的数组是一种 引用数据类型.不属于基本数据类型.数组的父类是 Object. 2.数组实际上是一个容器,可以同时容纳多个元素.(数组是一个数据的集合) 3.数组当中可以存储"基本数据类型"的数据,也可以存储"引用数据类型"的数据. 4.数组因为是引用类型,所以数组对象存储在 堆内存 当中.(数组是存储在堆当中的) 5.数组当中如果存储的是"java对象"的话,实际上存储的是对象的"引用(内存地址)&quo

  • JavaSwing基础之Layout布局相关知识详解

    一.View layout方法 首先,还是从ViewRootImpl说起,界面的绘制会触发performMeasure.performLayout方法,而在performLayout方法中就会调用mView的layout方法开始一层层View的布局工作. private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth, int desiredWindowHeight) { final View ho

  • 一篇文章带你了解Java基础-抽象

    目录 Java基础知识(抽象) 抽象 抽象定义 abstract的使用 定义抽象类 抽象类的一些注意点 总结 Java基础知识(抽象) 抽象 抽象是从众多的事物中抽取出共同的.本质性的特征,而舍弃其非本质的特征的过程.具体地说,抽象就是人们在实践的基础上,对于丰富的感性材料通过去粗取精.去伪存真.由此及彼.由表及里的加工制作,形成概念.判断.推理等思维形式,以反映事物的本质和规律的方法. 抽象定义 在继承过程中,我们知道父类的方法可以子类进行重写,而每个子类各自的实现都不尽相同.就好比动物都有吃

  • Java基础知识汇总

    Java基础知识 1.Java语言的优点: 1)Java是纯面向对象语言 2)与平台无关性,一次编译到处运行 3)Java提供了狠多内置类库 4)提供了对web应用的支持 5)具有较好的安全性(数组边界检测.Bytecode检测)和健壮性(强制型机制.垃圾回收器.异常处理) 6)去除c++难以理解的一些特性(头文件 指针 运算符重载 多重继承) 2.java与c++的异同: 1)Java为解释型语言,c++为编译型语言,java会慢但是跨平台 2)Jave为纯面向对象,c++既面向对象又能面向过

  • java 基础知识之IO总结

    java  基础知识之IO总结     我计划在接下来的几篇文章中快速回顾一下Java,主要是一些基础的JDK相关的内容. 工作后,使用的技术随着项目的变化而变化,时而C#,时而Java,当然还有其他一些零碎的技术.总体而言,C#的使用时间要更长一些,其次是Java.我本身对语言没有什么倾向性,能干活的语言,就是好语言.而且从面向对象的角度来看,我觉得C#和Java对我来说,没什么区别. 这篇文章主要回顾Java中和I/O操作相关的内容,I/O也是编程语言的一个基础特性,Java中的I/O分为两

  • java 基础知识之网络通信(TCP通信、UDP通信、多播以及NIO)总结

    java 基础知识之网路通信总结 在这篇文章里,我们主要讨论如何使用Java实现网络通信,包括TCP通信.UDP通信.多播以及NIO. TCP连接 TCP的基础是Socket,在TCP连接中,我们会使用ServerSocket和Socket,当客户端和服务器建立连接以后,剩下的基本就是对I/O的控制了. 我们先来看一个简单的TCP通信,它分为客户端和服务器端. 客户端代码如下: 简单的TCP客户端 import java.net.*; import java.io.*; public class

随机推荐