首页 技术 正文
技术 2022年11月15日
0 收藏 775 点赞 2,360 浏览 2160 个字

本文章内容整理自:张孝祥_Java多线程与并发库高级应用视频教程

当两条线程访问同一个资源时,可能会出现安全隐患。以打印字符串为例,先看下面的代码:

//
public class Test2 {
public static void main(String[] args) {
new Test2().init();
} public void init(){
final Outputer c = new Outputer();
Thread thread1 = new Thread(new Runnable() { @Override
public void run() { while (true) {
try {
Thread.sleep();
} catch (InterruptedException e) {
e.printStackTrace();
}
c.output("aaaaa");
} }
});
thread1.start();
Thread thread2 = new Thread(new Runnable() { @Override
public void run() { while(true){
try {
Thread.sleep();
} catch (InterruptedException e) {
e.printStackTrace();
}
c.output("bbbbb");
} }
});
thread2.start();
} class Outputer{
public void output(String name){ for (int i = ; i < name.length(); i++) {
System.out.print(name.charAt(i));
}
System.out.println(); }
}
}

在以上代码中,thread1和thread2都调用了output方法,理想的情况下,当thread1调用output方法时,应该一次性打印完“aaaaa”,而当thread2调用output方法,也是一次性打印完“bbbbb”。但在实际的运行中,会出现打印出诸如“aabbbaaa”这种情况,也就是说,thread1正在调用output方法时,thread2插了进来,两个线程同时操作了一个对象中的同一个方法。

为了避免这种情况,我们要求,当某个线程在调用output方法时,不允许其他线程调用。概括一下,即当某个线程在执行一段代码时,不允许其他线程执行这段代码。我们把这种行为,叫做线程互斥。

要实现线程互斥,最简单的方法就是加同步锁。

加同步锁的方式有两种。

第一种是同步代码块,以上面的代码为例,加同步代码块应该这么加:

    class Outputer{
public void output(String name){
synchronized (this) {
for (int i = ; i < name.length(); i++) {
System.out.print(name.charAt(i));
}
System.out.println();
}
}
}

在上面的代码中,“synchronized (this)”中的“this”被称为锁栓(也有别的叫法,在这里姑且先这么叫吧)。多个需要互斥的线程必须使用同一个对象当锁栓。在这段代码中,“this”指Outputer对象,而两条线程使用的是同一个Outputer对象,所以可以达到互斥效果。

第二种方式是声明同步方法,写法如下:

        public synchronized void output2(String name){
System.out.println(this.getClass());
for (int i = ; i < name.length(); i++) {
System.out.print(name.charAt(i));
}
System.out.println();
}

现在有一个问题,加入thread1调用output1,thread2调用output2,可以实现线程互斥吗?

答案是可以的。

同步方法使用的锁栓就是“this”。当同步代码块也使用“this”当锁栓时,这两个地方的代码就共用了同一个对象当锁栓,当某个线程进入其中一个时,另一个也被锁住了,不让其他线程进来。

那么,静态同步方法使用的锁栓是什么呢?

以下面这段代码为例:

    static class Outputer{
public static synchronized void output3(String name){
for (int i = ; i < name.length(); i++) {
System.out.print(name.charAt(i));
}
System.out.println();
}
}

它的同步锁是Outputer.class,即类的字节码对象。

最后说一说线程同步和线程互斥的关系。

同步是一种更为复杂的互斥,而互斥是一种特殊的同步。

  也就是说互斥是两个线程之间不可以同时运行,他们会相互排斥,必须等待一个线程运行完毕,另一个才能运行,而同步也是不能同时运行,但他是必须要安照某种次序来运行相应的线程(也是一种互斥)!

  总结:

  互斥:是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的。

  同步:是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的有序访问。在大多数情况下,同步已经实现了互斥。

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,078
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,553
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,402
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,177
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,814
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,898