您的位置:首页 > 编程语言 > Java开发

java多线程学习

2015-08-22 11:25 218 查看
从今天开始学习java多线程,平时自己写的程序很少用到多线程,也导致对于多线程这里一直不是很理解,接下来着重研究多线程。

多线程的安全问题

当我们有多个线程对同一个资源进行操作的时候,就会出现多线程安全问题,比如,A线程对一个资源设置值,B线程从同样的资源获取A资源设置的值,有可能在A没有完全设置完成,B线程就获取了执行权,此时就会出现多线程安全问题,这样说,大家可能不太理解,看下代码:

Resource.java

package com.test.safe;

public class Resource {

    String name;
    String sex;

}


A.java

package com.test.safe;

public class A implements Runnable {

    private Resource resource;

    public A(Resource resource) {
        this.resource = resource;
    }

    @Override
    public void run() {
        boolean isEng = true;
        while(true) {
            if (isEng) {
                resource.name = "jerry";
                resource.sex = "woman";
                isEng = false;
            } else {
                resource.name = "杰瑞";
                resource.sex= "男孩";
                isEng = true;
            }
        }
    }
}


B.java

package com.test.safe;

public class B implements Runnable {

    private Resource resource;

    public B(Resource resource) {
        this.resource = resource;
    }

    @Override
    public void run() {
        while (true) {
            System.out.println(resource.name+"======="+resource.sex);
        }
    }
}


代码比较简单,这里A和B线程使用的是同一个资源,A资源设置resource的值,B线程获取resource的值。这里为了保证A,B两个线程操作的是同一个资源,使用了通过构造方法来初始化。为了区分效果,这里A线程分别设置不同的值。

测试代码:

Resource resource = new Resource();
new Thread(new A(resource)).start();
new Thread(new B(resource)).start();


此时打印结果如下:




可以看到这里就出现了线程安全问题。为什么会出现这样的问题呢??比如A线程对name赋值为jerry之后,还没来得及给sex设置woman值,此时线程的执行权就被B线程获取到了,所以会获取到的是”jerry======男孩”

解决线程安全问题

我们可以在两个线程操作同一个资源的地方使用synchronized为其加上锁即可。

A.java

synchronized (resource) {
    if (isEng) {
        resource.name = "jerry";
        resource.sex = "woman";
        isEng = false;
    } else {
        resource.name = "杰瑞";
        resource.sex= "男孩";
        isEng = true;
    }
}


B.java

synchronized (resource) {
        System.out.println(resource.name+"======="+resource.sex);
}


这里操作的都是同一个对象,resource,为了保证两个线程使用的同一个锁,所以synchronized中的对象必须唯一,这里使用了resoure对象保证唯一性。

此时输出结果如下:




可以看到此时已经正常输出了。

等待唤醒机制

虽然我们加了同步锁可是大家又没有发现,有一个问题,就是每次输出一大片中文,在输出一大片英文,如果我们想设置一个,在输出一个,应该怎么实现??这里就需要使用到等待唤醒机制。



这里在Resource.java中定义一个标记,由于该标记必须唯一,所以放在了Resource.java中,用来标记当前线程是否可以获取执行权:

package com.test.safe;

public class Resource {

    String name;
    String sex;
    boolean flag = false;

}


此时A线程的run方法如下:

@Override
    public void run() {
        boolean isEng = true;
        while(true) {
            synchronized (resource) {
                if (resource.flag) {//如果当前flag==true,表示B线程正在执行,此时需要等待,等待期间,后边的代码是不会执行的。
                    try {
                        resource.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                if (isEng) {
                    resource.name = "jerry";
                    resource.sex = "woman";
                    isEng = false;
                } else {
                    resource.name = "杰瑞";
                    resource.sex= "男孩";
                    isEng = true;
                }
                resource.flag = true; //A线程设置数据执行结束,将flag设置为true,表示线程池中的其他线程可以获得线程的执行权了
                resource.notify(); //唤醒使用同一个锁的线程,这里就是B线程
            }
        }
    }


B线程的run方法如下:

@Override
    public void run() {
        while (true) {
            synchronized (resource) {
                if (!resource.flag) {//B线程正好和A线程相反
                    try {
                        resource.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(resource.name+"======="+resource.sex);
                resource.flag = false;
                resource.notify();
            }
        }
    }


此时运行的效果如下:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: