多线程入门三
问题一:多线程之间如何实现通讯
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.作者投稿可能会经我们编辑修改或补充。