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

Java学习笔记(多线程_2)

2015-11-30 18:37 537 查看

15 多线程

15.3 多线程间通信

15.3.1 线程间通信方法

多个线程在操作统一资源,但操作的动作不同。

等待唤醒机制:

例1:

class Res{
String name;
String sex;
boolean flag = false;
}

class Input implements Runnable{
Res r = new Res();
Input(Res r){
this.r = r;
}
public void run(){

int x = 0;
while(true){
synchronized(r){//输入和输出采用同一个锁
if(r.flag){
try {
r.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if(x==0){
r.name = "李雷";
r.sex = "男";
}else{
r.name = "韩梅梅";
r.sex = "女";
}
x = (x+1)%2;
r.flag = true;
r.notify();
}
}
}
}

class Output implements Runnable{
Res r = new Res();
Output(Res r){
this.r = r;
}
public void run() {
while(true){
synchronized(r){
if(!r.flag){
try {
r.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(r.name+"..."+r.sex);
r.flag= false;
r.notify();
}
}
}

}

public class InputOutputDemo {
public static void main(String[] args) {
Res r = new Res();
Input in = new Input(r);
Output out = new Output(r);

Thread t1 = new Thread(in);
Thread t2 = new Thread(out);

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


运行结果:


上述代码中输入一个输出一个的机理:等待唤醒机制。

多线程加了同步依然不安全需检查是否满足以下三个条件:

是否存在两个以上线程;

两个线程是否均同步;

是否应用同一个锁,必须用同一锁。

wait()、notify()和notifyAll()都是用在同步中,因为都需要持有锁(监视器monitor)的线程操作,而只有同步中才有锁。

等待和唤醒必须用同一个锁,锁可以用任意Object对象,所以可以被任意对象调用的方法定义Object类中。

例2(例1优化):

class Res{
private String name;
private String sex;
private boolean flag = false;

public synchronized void set(String name,String sex){
if(flag)
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
this.name = name;
this.sex = sex;
this.flag = true;
this.notify();
}

public synchronized void out(){
if(!this.flag){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(name+"..."+sex);
this.flag= false;
this.notify();

}
}

class Input implements Runnable{
Res r = new Res();
Input(Res r){
this.r = r;
}
public void run(){
int x = 0;
while(true){
if(x==0){
r.set("李雷", "男");
}else{
r.set("韩梅梅", "女");
}
x = (x+1)%2;
}
}
}

class Output implements Runnable{
Res r = new Res();
Output(Res r){
this.r = r;
}
public void run() {
while(true){
r.out();
}
}

}

public class InputOutputDemo {
public static void main(String[] args) {
Res r = new Res();

Thread t1 = new Thread(new Input(r));
Thread t2 = new Thread(new Output(r));

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


两个对象多个线程问题:

class Res{
private String name;
private String sex;
private boolean flag = false;
private int count = 1;

public synchronized void set(String name,String sex){
while(flag)
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
this.name = name+count;
this.sex = sex;
count++;
System.out.println("设置"+this.name+"..."+sex);
this.flag = true;
this.notifyAll();//需全部唤醒,否则按等待顺序下一个还是set,会覆盖之前的set
}

public synchronized void out(){
while(!this.flag){//由于存在多个线程,每次拿到锁都必须判断
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("输出..."+name+"..."+sex);
this.flag= false;
this.notifyAll();

}
}

class Input implements Runnable{
Res r = new Res();
Input(Res r){
this.r = r;
}
public void run(){
int x = 0;
while(true){
if(x==0){
r.set("李雷", "男");
}else{
r.set("韩梅梅", "女");
}
x = (x+1)%2;
}
}
}

class Output implements Runnable{
Res r = new Res();
Output(Res r){
this.r = r;
}
public void run() {
while(true){
r.out();
}
}

}

public class InputOutputDemo {
public static void main(String[] args) {
Res r = new Res();

Thread t1 = new Thread(new Input(r));
Thread t2 = new Thread(new Input(r));
Thread t3 = new Thread(new Output(r));
Thread t4 = new Thread(new Output(r));

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


运行结果:


注意:

while判断和notify会导致死锁出现。

15.3.2 JDK1.5特性

Jdk1.5中将同步和锁封装为对象,并将操作锁的隐式方式定义到该对象中,将隐式动作变为显示动作。

同步中synchronized替换为了Lock,Condition 替代了 Object 监视器方法的使用。

Lock接口可以在一个锁上加上多组监视器。

Condition接口:出现替代了Object中的wait、notify、notifyAll方法。将这些监视器方法单独进行了封装,变成Condition监视器对象,可以任意锁进行组合。

Condition接口中的await方法对应于Object中的wait方法。

Condition接口中的signal方法对应于Object中的notify方法。

Condition接口中的signalAll方法对应于Object中的notifyAll方法。

import java.util.concurrent.locks.*;

class Res{
private String name;
private String sex;
private boolean flag = false;
private int count = 1;
//创建一个锁对象
private Lock lock = new ReentrantLock();
//通过已有锁获取两组监视器,一组监视设置函数,一组监视输出函数
private Condition con_set = lock.newCondition();
private Condition con_out = lock.newCondition();

public void set(String name,String sex) throws InterruptedException{
lock.lock();
try{
while(flag)
con_set.await();
this.name = name+count++;
this.sex = sex;

System.out.println("设置"+this.name+"..."+sex);
flag = true;
con_out.signalAll();
}finally{

lock.unlock();
}
}

public void out() throws InterruptedException{
lock.lock();
try{
while(!flag){//由于存在多个线程,每次拿到锁都必须判断
con_out.await();
}
System.out.println("输出..."+name+"..."+sex);
flag= false;
con_set.signalAll();
}finally{
lock.unlock();
}
}
}

class Input implements Runnable{
Res r = new Res();
Input(Res r){
this.r = r;
}
public void run(){
int x = 0;
while(true){
if(x==0){
try {
r.set("李雷", "男");
} catch (InterruptedException e) {
e.printStackTrace();
}
}else{
try {
r.set("韩梅梅", "女");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
x = (x+1)%2;
}
}
}

class Output implements Runnable{
Res r = new Res();
Output(Res r){
this.r = r;
}
public void run() {
while(true){
try {
r.out();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

public class InputOutputDemo {
public static void main(String[] args) {
Res r = new Res();

Input in = new Input(r);
Output out = new Output(r);

Thread t1 = new Thread(in);
Thread t2 = new Thread(in);
Thread t3 = new Thread(out);
Thread t4 = new Thread(out);

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


运行结果:


15.3.3 线程停止

开启多线程通常为循环结构,只要控制循环,就可以让run方法结束,即线程结束。

特殊情况:

线程处于冻结状态,无法读取标记,程序无法结束。

可以使用Thread中的interrupt()方法将线程从冻结强制恢复至运行状态,按api中的描述:

“如果线程在调用 Object 类的 wait()、wait(long) 或 wait(long, int) 方法,或者该类的 join()、join(long)、join(long, int)、sleep(long) 或 sleep(long, int) 方法过程中受阻,则其中断状态将被清除,它还将收到一个 InterruptedException。”

此时会抛出InterruptedException异常,则进行相应处理。

public class StopThreadDemo {
public static void main(String[] args) {
StopThread st = new StopThread();

Thread t1 = new Thread(st);
Thread t2 = new Thread(st);

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

int num = 0;

while(true){
if(num++ == 60){
t1.interrupt();
t2.interrupt();
break;
}
System.out.println(Thread.currentThread().getName()+"..."+num);
}
System.out.println("over");
}
}

class StopThread implements Runnable{
private boolean flag = true;
public synchronized void run(){
while(flag){
try {
wait();
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName()+"..Exception");
flag =false;
}
System.out.println(Thread.currentThread().getName()+"..run");
}
}
public void changeFlag(){
flag = false;
}
}


运行结果:


15.3.4 其他方法

setDaemon()方法:



public class StopThreadDemo {
public static void main(String[] args) {
StopThread st = new StopThread();

Thread t1 = new Thread(st);
Thread t2 = new Thread(st);
t1.setDaemon(true);
t2.setDaemon(true);
t1.start();
t2.start();

int num = 0;

while(true){
if(num++ == 60){

break;
}
System.out.println(Thread.currentThread().getName()+"..."+num);
}
System.out.println("over");
}
}

class StopThread implements Runnable{
private boolean flag = true;
public synchronized void run(){
while(flag){
try {
wait();
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName()+"..Exception");
flag =false;
}
System.out.println(Thread.currentThread().getName()+"..run");
}
}
}


运行结果:


ps:作为守护线程,主线程停止,守护线程也停止。

yield方法

public static void yield()

暂停当前正在执行的线程对象,并执行其他线程。

setPriority方法

public final void setPriority(int newPriority)

更改线程的优先级。

首先调用线程的 checkAccess 方法,且不带任何参数。这可能抛出 SecurityException。

在其他情况下,线程优先级被设定为指定的 newPriority 和该线程的线程组的最大允许优先级相比较小的一个。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: