线程:是进程的一部分
---实现多线程的两种方式
---创建一个类实现Runnable接口,以这个类的对象作为创建Thread类的对象的构造函数的参数
---直接继承Thread类,重写run方法
---在main函数中有t.join()---即等线程t结束后,当前线程(main)才能执行
---Thread.yeild()---主动放弃CPU的使用权进入ready状态
---设置优先级---t.setPriority()---参数为Thread.MAX_PRIORITY--最高优先级;MIN_PRIORITY---最低优先级
---守护线程---在没有用户线程时,自动离开,这个线程有最低的优先级
eg: java垃圾回收线程---当我们的程序不再有运行中的Thread,程序就不会产生垃圾,当成为虚 拟机上仅剩的线程时 ,java虚拟机会自动离开---运行后台的一种特殊线程---不依赖线程,依 赖系统
t.setDaemon(true)--设置t线程为守护线程
---同步块---eg:多个线程共享同一数据的问题---每个对象对应一把锁
package guo;
public class A {
public static void main(String[] args) {
Object resource=new Object();
MyThread mt1=new MyThread(resource,"MT1");
MyThread mt2=new MyThread(resource,"MT2");
mt1.start();
mt2.start();
}
}
//自定义的线程类
class MyThread extends Thread{
private Object resource;
public MyThread(){}
public MyThread(Object resource,String name){
this.resource=resource;
this.setName(name);
}
public void run(){
synchronized(resource){//同步语句块
System.out.println(this.getName()+"线程访问了资料!!!");
System.out.println(this.getName()+"线程带着锁睡觉去了!!!");
try{
Thread.sleep(5000);//睡5000ms后醒来
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println(this.getName()+"线程带着锁睡醒后释放了锁!!!");
}
}
}
/**
* 此程序运行的结果为:
* MT1线程访问了资料!!!
* MT1线程带着锁睡觉去了!!!
* MT1线程带着锁睡醒后释放了锁!!!
* MT2线程访问了资料!!!
* MT2线程带着锁睡觉去了!!!
* MT2线程带着锁睡醒后释放了锁!!!
*/
---同步函数---每个类的实例对应一把锁---方法一旦执行就独占锁---静态方法用的锁是该方法所属类的字节码对 象上的锁
package guo;
public class Single1 {
public static void main(String[] args) {
A2 a = new A2();
Thread t1 = new Thread(a);
Thread t2 = new Thread(a);
t1.start();
t2.start();
}
}
class A2 implements Runnable {
int i;
@Override
public void run() {
doSomeThing();
}
/*同步函数一样是需要获取一把钥匙,该钥匙是哪个对象的呢?*/
public synchronized void doSomeThing() {
for (int j = 1; j <= 10; j++) {
int h = i + 1;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
i = h;
System.out.println(i);
}
}
}
---线程间的通讯问题
---通过管道流的方式---简单、效率低,复杂数据和对象不好处理
package guo;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.util.Random;
public class Single2 {
public static void main(String[] args) {
try {
PipedInputStream in = new PipedInputStream();
PipedOutputStream out = new PipedOutputStream(in);
PipedSend send = new PipedSend(out);
PipedRec rec = new PipedRec(in);
Thread t1 = new Thread(send);
Thread t2 = new Thread(rec);
t1.start();
t2.start();
} catch (Exception e) {
e.printStackTrace();
}
}
}
class PipedSend implements Runnable {
OutputStream out;
public PipedSend(OutputStream out) {
this.out = out;
}
@Override
public void run() {
for (int i = 1; i <= 5; i++) {
byte theValue = (byte) new Random().nextInt(256);
try {
out.write(theValue);
System.out.println("send the value is:" + theValue);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
class PipedRec implements Runnable {
InputStream in;
public PipedRec(InputStream in) {
this.in = in;
}
@Override
public void run() {
for (int i = 1; i <= 5; i++) {
try {
byte theValue = (byte) in.read();
System.out.println("receive the value is:" + theValue);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
/**
* 运行结果是:
* send the value is:61
* send the value is:17
* send the value is:63
* send the value is:-81
* send the value is:94
* receive the value is:61
* receive the value is:17
* receive the value is:63
* receive the value is:-81
* receive the value is:94
*/
---生产者和消费者---用yeild方法处理---不叫耗资源、安全性低
package guo;
import java.util.Random;
public class Demo11 {
public static void main(String[] args) {
FlagSend send = new FlagSend();
FlagRec rec = new FlagRec(send);
Thread t1 = new Thread(send);
Thread t2 = new Thread(rec);
t2.setDaemon(true);
t1.start();
t2.start();
}
}
//生产者
class FlagSend implements Runnable{
boolean flag;
int theValue;
@Override
public void run() {
for(int i = 0; i < 5;i++){
while(flag){
Thread.yield();
}
theValue = new Random().nextInt(1000);
flag = true;
System.out.println("send the value is:"+theValue);
}
}
}
//消费者---->把生产的对象作为自己的成员
class FlagRec implements Runnable{
FlagSend send;
public FlagRec(FlagSend send){
this.send = send;
}
@Override
public void run() {
while(true){//死循环
while(!send.flag){
Thread.yield();
}
System.out.println("receiver the value is:"+send.theValue);
send.flag = false;
}
}
}
---wait notify来交互
这两个方法不是线程的方法,是Object类的方法,每个对象上都可以拥有一个线程等待池,挂在这个对象 上的线程,就可以通过这个对象去让线程等待和唤醒,wait和notify必须放在同步块中
package guo;
import java.util.Random;
public class WaitTest {
public static void main(String[] args) {
WaitSend send = new WaitSend();
WaitRec rec = new WaitRec(send);
Thread t1 = new Thread(send);
Thread t2 = new Thread(rec);
t2.setDaemon(true);
t1.start();
t2.start();
}
}
//生产者
class WaitSend implements Runnable{
boolean flag;
int theValue;
@Override
public void run() {
for(int i = 1; i <= 5;i++){
synchronized (this) {//wait notify 必须放入同步块
while(flag){//while循环 而不是if 存在虚假唤醒
try {
this.wait();//wait方法会释放钥匙
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/*制造食物*/
theValue = new Random().nextInt(10000);
System.out.println("send the value is:"+theValue);
/*让自己进入阻塞*/
flag = true;
/*唤醒该对象上其它等待线程*/
this.notify();
}
}
}
}
/*生产者线程和消费者线程 的等待和唤醒必须通过同一个对象
* 同步块必须使用同一个锁同一把钥匙
*/
class WaitRec implements Runnable{
WaitSend send;
public WaitRec(WaitSend send){
this.send = send;
}
@Override
public void run() {
while(true){
synchronized (send) {
while(!send.flag){
try {
send.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/*消费食物*/
System.out.println("receiver theValue is:"+send.theValue);
/*自己进入阻塞状态*/
send.flag = false;
/*唤醒生产者*/
send.notify();
}
}
}
}