多线程入门三

问题一:多线程之间如何实现通讯

1、什么是多线程之间通讯

多线程之间的通讯:本质就是多个线程操作同一资源,但操作的动作不相同。

2、多线程之间的通讯需求:

功能需求:一个线程向磁盘文件中写入文件内容,一个线程读取磁盘文件的内容

核心代码实现:

1、文件资源共享类(文件属性和是否可读标识(默认初始值为不可读,false)) 

package com.zzg.communication;

import java.io.File;

/**
 * 磁盘文件资源类
 * @author Administrator
 *
 */
public class Resource {
	private File file;
	
	private boolean target = false;
	
	public File getFile() {
		return file;
	}
	public void setFile(File file) {
		this.file = file;
	}
	public boolean isTarget() {
		return target;
	}
	public void setTarget(boolean target) {
		this.target = target;
	}
	
	public Resource(File file) {
		super();
		this.file = file;
	}
	
	

}

2、写入线程资源类:

package com.zzg.communication;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * 写入磁盘文件线程
 * 
 * @author Administrator
 *
 */
public class InputResource implements Runnable {
	private Resource resource;

	public Resource getResource() {
		return resource;
	}

	public void setResource(Resource resource) {
		this.resource = resource;
	}

	public InputResource(Resource resource) {
		super();
		this.resource = resource;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		synchronized (resource) {
			// 磁盘文件是否可读状态
			if (!resource.isTarget()) {
				byte bytes[] = new byte[512];
				bytes = "Hello".getBytes();
				int b = bytes.length; // 是字节的长度,不是字符串的长度
				FileOutputStream fos;
				try {
					fos = new FileOutputStream(resource.getFile());
					fos.write(bytes, 0, b);
					fos.write(bytes);
					fos.close();
				} catch (FileNotFoundException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				// 变更标识位
				resource.setTarget(true);
				// 唤醒其他正在等待的线程
				resource.notifyAll();

			} else {
				// 当前线程变为等待,释放resource 锁
				try {
					resource.wait();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}

}

3、读取线程资源:

package com.zzg.communication;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;

public class OutputResource implements Runnable {
	private Resource resource;

	public Resource getResource() {
		return resource;
	}

	public void setResource(Resource resource) {
		this.resource = resource;
	}

	public OutputResource(Resource resource) {
		super();
		this.resource = resource;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		synchronized (resource) {
			// 磁盘文件是否存在资源
			if (resource.isTarget()) {
				StringBuffer buffer = new StringBuffer();
				try {
					FileInputStream inputStream = new FileInputStream(resource.getFile());
					String line; // 用来保存每行读取的内容
					BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
					line = reader.readLine(); // 读取第一行
					while (line != null) { // 如果 line 为空说明读完了
						buffer.append(line); // 将读到的内容添加到 buffer 中
						buffer.append("\n"); // 添加换行符
						line = reader.readLine(); // 读取下一行
					}
					reader.close();
					inputStream.close();
				} catch (FileNotFoundException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
				// 清空指定文件内容
				this.clean(resource.getFile());
				// 输出文件内容
				System.out.println("File Content is:" + buffer.toString());
				// 变更标识位
				resource.setTarget(false);
				// 唤醒其他正在等待的线程
				resource.notifyAll();
			} else {
				// 当前线程变为等待,释放resource 锁
				try {
					resource.wait();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}

	/**
	 * 清理指定文件内容
	 */
	public void clean(File file) {
		FileWriter fileWriter;
		try {
			fileWriter = new FileWriter(file);
			fileWriter.write("");
			fileWriter.flush();
			fileWriter.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
	}

}

4、多线程测试类:

package com.zzg.communication;

import java.io.File;
import java.io.IOException;

public class ThreaCommun {

	public static void main(String[] args) throws IOException {
		// 判断指定文件是否存在,不存在及创建
		File file = new File("E:\\resource.txt");
		if (!file.exists()) {
			file.createNewFile();
		}
		Resource resource = new Resource(file);
		
		Thread one = new Thread(new InputResource(resource));
		Thread two = new Thread(new OutputResource(resource));
		one.start();
		two.start();
	}

}

 

多线程之间通讯总结:wait()、notify()和notifyAll()方法

          wait()、notify()、notifyAll()是三个定义在Object类里的方法,可以用来控制线程的状态。这三个方法最终调用的都是jvm级的native方法。随着jvm运行平台的不同可能有些许差异。

1、如果对象调用了wait方法就会使持有该对象的线程把该对象的控制权交出去,然后处于等待状态。

2、如果对象调用了notify方法就会通知某个正在等待这个对象的控制权的线程可以继续运行。

3、如果对象调用了notifyAll方法就会通知所有等待这个对象控制权的线程继续运行。

 

二、多线程安全之Lock

简介: 在 jdk1.5 之后,并发包中新增了 Lock 接口(以及相关实现类)用来实现锁功能,Lock 接口提供了与 synchronized 关键字类似的同步功能,但需要在使用时手动获取锁和释放锁。

实例:多线程模拟售票(Lock版本)

package com.zzg.lock;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ThreeLock implements Runnable {
	private Integer ticket = 100;
	Lock lock = new ReentrantLock();

	@Override
	public void run() {
		// TODO Auto-generated method stub
		while (ticket > 0) {
			// 售票方法调用

			lock.lock();
			try {
				sale();
			} finally {
				lock.unlock();
			}

		}
	}

	public void sale() {

		if (ticket > 0) {

			try {
				Thread.sleep(10);
			} catch (Exception e) {

			}

			System.out.println(Thread.currentThread().getName() + ",出售 第" + (100 - ticket + 1) + "张票.");
			ticket--;
		}

	}

	public static void main(String[] args) {
		ThreeLock three = new ThreeLock();
		// 共享线程three中ticket 属性
		Thread thread1 = new Thread(three);
		Thread thread2 = new Thread(three);
		thread1.start();
		thread2.start();
	}

}

Lock 语法规则:

Lock lock  = new ReentrantLock();
lock.lock();
try{
    //可能会出现线程安全的操作
}finally{
    //一定在finally中释放锁
    //也不能把获取锁在try中进行,因为有可能在获取锁的时候抛出异常
      lock.ublock();
}

 

Condition用法:

Condition的功能类似于在传统的线程技术中的,Object.wait()和Object.notify()的功能。

Condition condition = lock.newCondition();
res. condition.await();  类似wait
res. Condition. Signal() 类似notify

 

三、如何正确的关闭线程

推荐:使用退出标志,使线程正常退出,也就是当run方法完成后线程终止。

package com.zzg.lock;

public class StopThread implements Runnable {
	// 线程运行状态标识符,默认值为true
	private boolean target = true;

	public boolean isTarget() {
		return target;
	}

	public void setTarget(boolean target) {
		this.target = target;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		System.out.println("线程开始执行!");

		while (target) {
			// 执行线程的业务逻辑
			for (int i = 1; i < 6; i++) {
				System.out.println("执行了[" + i + "]次");
			}

		}
		System.out.println("线程结束执行!");

	}
	
	public static void main(String[] args) {
		System.out.println("主线程开始执行!");
		StopThread stop = new StopThread();
		Thread thread = new Thread(stop);
		thread.start();
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		stop.setTarget(false);
		System.out.println("主线程结束执行!");

	}
	

}

四、守护线程

Java中有两种线程,一种是用户线程,另一种是守护线程。当进程不存在或主线程停止,守护线程也会被停止。使用setDaemon(true)方法设置为守护线程

 

五、线程优先级

在JAVA线程中,通过一个int priority来控制优先级,范围为1-10,其中10最高,默认值为5。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值