- 引言
- Java多线程中的类锁
- 1 注意区分类锁和对象锁的区别
- Java中的死锁现象
- 1 最低级的线程死锁现象
- volatile关键字
- 1 同步死循环问题
- 2 解决死循环记住
1.引言
在此篇博客中,主要介绍一下,在Java多线程中的:类锁,死锁,以及volatile
关键字。
2.Java多线程中的类锁
在上一篇博客中我们使用了下面的代码:
public synchronized boolean saleTicket() throws Exception
{
//代码
}
在上篇博客中我们介绍了,这样其实就是给该方法加锁:加的是对象锁,对象就是this
注意:
1.该方法不是静态方法,如果是静态方法呢?静态方法就不是this了。
2.这很好理解,如果是静态方法,在私用该方法的时候,说不定都没有this对象
- 现在我们把代码改成这样(方法变成了静态方法)
public synchronized static void saleTicket()
{
System.out.println("我在卖票了");
}
上述代码等价于
public class Ticket {
public static void saleTicket()
{
synchronized (Ticket.class) {
System.out.println("我在卖票了");
}
}
}
此时我们是给方法添加了一个类锁。
2.1 注意区分类锁和对象锁的区别
public class Ticket {
public synchronized static void saleTicket1()
{
System.out.println("我在卖票了");
}
public synchronized void saleTicket2()
{
System.out.println("我在卖票了");
}
}
注意:
1.这两个方法给对象加的锁是不一样的,一个是类锁,一个是this对象锁
2.当线程1访问saleTicket1方法的同时拿到类锁
3.当线程2访问saleTicket2是要拿this对象锁(哪怕线程1未释放锁)。两者是不影响的
3. Java中的死锁现象
在Java多线程编程当中,一定要避免死锁现象。死锁现象一产生很容易造成线程假死现象。这种错误是非常难排查的。
3.1 最低级的线程死锁现象
- 代码如下
public class Ticket {
private Object o1=new Object();
private Object o2=new Object();
public void saleTicket1()
{
synchronized (o1) {
System.out.println("拿到o1");
synchronized (o2) {
System.out.println("拿到o2");
}
}
}
public void saleTicket2()
{
synchronized (o2) {
System.out.println("拿到o2");
synchronized (o1) {
System.out.println("拿到o1");
}
}
}
}
1.如果线程1访问saleTicket1方法。线程2访问saleTicket2方法
2.线程1拿到o1锁,线程2拿到o2锁,此时线程1等待o2锁,线程2等待o1锁:导致死锁
3.线程死锁是程序设计时的bug,我们应该尽量避免死锁现象的产生
4.volatile关键字
关键字volatile解决的问题主要是:变量在多个线程间可见。
4.1 同步死循环问题
- 首先我们创建一个打印字符串的类
public class PrintString {
private boolean flag = true;
public void setFlag(boolean flag) {
this.flag = flag;
}
public void printString() {
while (flag) {
System.out.println("打印字符串");
}
}
}
- 输入字符串的线程类
public class MyThread extends Thread {
PrintString p;
public MyThread(PrintString p) {
this.p=p;
}
@Override
public void run() {
p.printString();
}
}
- main函数
public class app {
public static void main(String[] args) throws InterruptedException {
PrintString p=new PrintString();
MyThread td=new MyThread(p);
td.start();
Thread.sleep(5000);
p.setFlag(false);
}
}
- 如果我们以服务器模式运行,这就是一个死循环
-server
4.2 解决死循环(记住)
- 只需要给共享数据添加一个关键字即可
public class PrintString {
volatile private boolean flag = true;
public void setFlag(boolean flag) {
this.flag = flag;
}
public void printString() {
while (flag) {
System.out.println("打印字符串");
}
}
}