多线程入门三

哈哈 阅读:570 2021-03-31 16:50:27 评论:0

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

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。

标签:多线程
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

关注我们

一个IT知识分享的公众号