您的位置:首页 > 职场人生

黑马程序员——线程的安全问题

2015-04-28 23:53 169 查看
------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------

线程出现安全问题的原因分析

是因为我们通过多个线程对同一数据进行操作时,它的时间片分配是随机的,有可能在票数递减后

线程就将时间片让出,这时其它的线程在执行时,就会在原来票数基础上在递减。

在展示时就会出现同票或负数问题.

这是多线程存在的一些安全问题.

线程安全问题的产生的条件

1. 必须是多线程程序

2. 多个线程操作同一个数据

3. 在操作同一个数据时有多条语句。

同步代码块的方式解决线程案例问题

解决线程安全问题的原理:

在对于有可能产生线程安全的代码,我们进行控制,让线程在执行时,

其它的线程不可以访问,我的线程执行完成后,其它线程才可以使用.

对于我们线程案例问题:可以使用同步来解决.

同步代码块

同步方法

同步代码块的格式:

Synchronized(任意一个对象){

可能出现安全问题的代码

}

我们在测试程序中使用了同步代码块

<span style="font-size:14px;">package cn.itcast.test;

//售票程序 implements Runnable
//100张速度与激情7票,三个窗口售卖。显示出每一个窗口买的票是什么?
//分析:
//1.定义出100张票

//2.定义窗口做售票操作

//3.有三个窗口来售票---需要三个线程,而线程中要执行的操作就是售票。
public class SellTicketDemo2 implements Runnable {

private boolean flag = true;
// 1.定义100张票
private int ticketNum = 100;
Object obj = new Object();

// 2.定义一个售票操作
public void sellTicket() {
// 第二个第三个线程在这个位置等待
synchronized (obj) {
if (ticketNum > 0) {

// 判断有票才卖
System.out.println("售出了第" + (ticketNum) + "张票");
// 将票递减
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}

ticketNum--;

} else {
stopSellTicket();// 停止售票

// Thread.currentThread().stop();
}
}
}

@Override
public void run() {

while (flag) {
sellTicket();
}
}

// 停止售票
public void stopSellTicket() {
flag = false;
}
}</span>


同步代码块的锁及同步方法应用和锁的问题

使用同步方法来解决问题

同步方法格式 :

在方法的修饰符上使用一个synchronized就可以。

public synchronized void sellTicket(){} 这就是一个同步方法.

与同步代码块的区别:

它们的原理是一样的,只不过同步代码块可以控制的范围更精确。

而同步方法只是对一个方法时行了同步。

问题:同步方法也要使用一个锁,它的锁是什么?

对于同步方法来说,它所使用的锁对象就是this.

注意:这时的同步方法不能是静态的,如果是静态的它的锁又是什么哪?

是本类的Class对象。

Java中的Class对象怎样获取?

简单获取方式就是 类名.class

package cn.itcast.test;

//售票程序 implements Runnable
//100张速度与激情7票,三个窗口售卖。显示出每一个窗口买的票是什么?
//分析:
//1.定义出100张票

//2.定义窗口做售票操作

//3.有三个窗口来售票---需要三个线程,而线程中要执行的操作就是售票。

//使用同步方法來解決线程安全问题
public class SellTicketDemo3 implements Runnable {

private static boolean flag = true;
// 1.定义100张票
private static int ticketNum = 100;

int x = 0;

// 2.定义一个售票操作 同步方法
public static synchronized void sellTicket() {

if (ticketNum > 0) {

// 判断有票才卖
System.out.println("售出了第" + (ticketNum) + "张票");
// 将票递减
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}

ticketNum--;

} else {
stopSellTicket();// 停止售票

}

}

// 它不是同步方法 在这个方法的同步块中所使用的锁是obj.
public void sellTicket2() {

synchronized (SellTicketDemo3.class) {
if (ticketNum > 0) {

// 判断有票才卖
System.out.println("售出了第" + (ticketNum) + "张票");
// 将票递减
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}

ticketNum--;

} else {
stopSellTicket();// 停止售票

}
}
}

@Override
public void run() {

while (flag) {

if (x % 2 == 0) {
sellTicket();
} else {
sellTicket2();
}
x++;
}
}

// 停止售票
public static void stopSellTicket() {
flag = false;
}
}


同步代码块(和同步方法)解决线程线程案例问题的解释

就是对我们在多线程程序中要操作的共享数据及对其进行操作的语句进行了加锁操作,

简单说,就是一个线程在执行这些代码时,其它的线程不能执行。

同步代码块可以对方法中一部分代码进行加锁。

而同步 方法是将所有的方法内的代码进行了加锁。

同步的特点及好处和弊端 以及同步代码块与同步方法选择

使用一个对象做为锁,所有的线程使用同一个锁,当一个线程使用它时,其它线程等待。

优点:可以解决我们多线程程序的安全问题.

缺点:使用了同步,会降低多线程程序的性能。并且有可能出现死锁问题.

同步代码块与同步方法使用哪一个?

同步代码块可以替换同步方法,同步方法不能替代同步代码块,所以在

精度控制上,同步代码块会更好,并且,使用同步代码块的效率也比较高。

所以我们一般选择使用同步代码块。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: