多线程--基础知识

一、线程的理解

       进程是程序的一种动态执行的实现,一个进程的实现需要多个线程的启动,线程与线程之间都是各自独立的。表面看是同时执行的,但其实是CPU会为它们分配时间片,并不是同时进行的。

二、创建线程的两种方式

(1)继承Thread

public class MyThread extends Thread{
	private String name;
	
	public MyThread(String name){
		this.name = name;
	}
        public void run(){
		for(int i=1;i<=10;i++){
			System.out.println(name+"运行"+i);
		}
	}
	
	public static void main(String[] args) {
		MyThread m1 = new MyThread("线程A");
		MyThread m2 = new MyThread("线程B");
		
		m1.start();
		m2.start();
	}
}

问题1:为什么不调用run()而调用start()呢?

答:因为通过Thread源码我们知道,实际调用的是start0(),它是native修饰的,它代表本机的操作系统函数,线程的启动需要底层操作系统的支持

try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
    }

    private native void start0();

问题2:同一线程可不可以多次调用start()呢?

答:不能,否则会报错 ---- IllegalThreadStateException

private volatile int threadStatus = 0;

public synchronized void start() {
        /**
         * This method is not invoked for the main method thread or "system"
         * group threads created/set up by the VM. Any new functionality added
         * to this method in the future may have to also be added to the VM.
         *
         * A zero status value corresponds to state "NEW".
         */
        if (threadStatus != 0)
            throw new IllegalThreadStateException();

        /* Notify the group that this thread is about to be started
         * so that it can be added to the group's list of threads
         * and the group's unstarted count can be decremented. */
        group.add(this);

        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
    }

问题3:必须要覆盖run()吗?

答:必须要覆盖,虽然Thread是实现Runnable接口的子类,但并没有完全实现run方法,此方法是Runnable的子类实现的,所以必须覆盖run方法

 @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }

(2)实现Runnable接口

public class MyThread2 implements Runnable{
	
	private String name;
	
	public MyThread2(String name){
		this.name = name;
	}
	@Override
	public void run() {
		for(int i=1;i<=10;i++){
			System.out.println(name+"运行"+i);
		}
		
	}
	
	public static void main(String[] args) {
		MyThread2 m1 = new MyThread2("a");
		MyThread2 m2 = new MyThread2("b");
		Thread t1 = new Thread(m1);
		Thread t2 = new Thread(m2);
		t1.start();
		t2.start();
	}

}

注意:因为Runnable接口中只有抽象的run方法,所以启动还是需要Thread类,Thread类中有接收Runnable子类的构造器。

三、资源共享问题

单继承Thread资源不会共享,Runnable实现类会资源共享

四、线程的状态

创建、就绪、运行、阻塞、终止

1.创建:Thread t  = new Thread();就是创建一个线程,但该线程只是有了内存空间并不具备运行能力

2.就绪:执行start()方法,具备了运行条件,在线程队列排队,等待CPU调度

3.运行:当前就绪的线程被调度并获得处理器资源,执行run()方法

4.阻塞:运行中的线程被人为的挂起,如sleep,wait等,进入阻塞状态,只有取消后才能进到就绪状态

5.终止:线程执行stop()或者run()执行完毕才会终止

问题:JAVA程序每次运行至少启动几个线程??

答:至少2个,一个是main线程,一个是垃圾收集线程。
具体说明:每当用java命令执行一个类时,都会启动一个JVM,每一个JVM实际上就是在操作系统上启动了一个进程,java本身具有垃圾收集的机制。

五、相关方法

(1)线程的强制运行 join()
可以让一个线程强制运行,其他线程必须等它执行完毕后才能执行
(2)线程的休眠sleep()
可以有延迟的效果
(3)中断线程 interrupt()
当一个线程执行时,另一个线程可以用该方法中断它
(4)后台线程
设置后台进程:setDaemon()
只要有一个前台线程没结束,JAVA进程就不会结束,后台进程是就算JAVA进程结束了,后台进程可以依然执行
(5)线程的优先级
最低: MIN 1  中等(默认,main线程): NORM 5  最高: MAX 10
优先级越高,被CPU优先调度的机会越大,就越先执行
(6)线程礼让   yield()
将一个线程的操作暂时让给其他线程执行

六、同步和死锁

(1)同步:如果是通过实现Runnable实现线程,操作类下的属性会资源共享,多个线程操作同一资源会出现资源同步问题。
解决办法:
同步代码块
synchronized(对象){}
同步方法
synchronized 返回值 方法名(){}
java定义方法完整格式: 访问权限 final static synchronized.....

public class 资源同步问题 {
	public static void main(String[] args) {
		MyThread21 t1 = new MyThread21();
		new Thread(t1, "A").start();
		new Thread(t1, "B").start();
		new Thread(t1, "C").start();
		
	}
}

class MyThread21 implements Runnable{
	private int ticket = 5;
	@Override
	public void run() {
		for(int i=0;i<100;i++){
				this.sale();
		}
		
	}
	
	public synchronized  void sale(){
		if(ticket>0){
			try {
				Thread.sleep(300);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName()+"运行---卖票:"+ticket--);
		}
	}

}

加了同步锁后不会产生卖票为负数的情况了

(2)死锁
同步可以保证同一资源的正确性,但是过多的同步容易导致死锁

/**
 * 张三:李四先把书给我,我再给他画
 * 李四:张三先把画给我,我再给他书
 * @author admin
 *
 */
public class 死锁问题 {
	public static void main(String[] args) {
		DeadThread dt1 = new DeadThread();
		DeadThread dt2 = new DeadThread();
		dt1.flag = true;
		dt2.flag = false;
		new Thread(dt1,"线程A").start();
		new Thread(dt2,"线程B").start();
	}
}

class Zhangsan {
	public void say(){
		System.out.println("李四先把书给我,我再给他画");
	}
	public void get(){
		System.out.println("李四把书还我了");
	}
}

class Lisi {
	public void say(){
		System.out.println("张三先把画给我,我再给他书");
	}
	public void get(){
		System.out.println("张三把画还我了");
	}
}


class DeadThread implements Runnable{
	private static Zhangsan zs = new Zhangsan();
	private static Lisi ls = new Lisi();
	boolean flag = false;
	
	@Override
	public void run() {
		if(flag){
			synchronized(zs){
				zs.say();
			
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			synchronized(ls){
				zs.get();
			}
			}
		}else{
			synchronized(ls){
				ls.say();
				
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			synchronized(zs){
				ls.get();
			}
			}
		}
		
	}
	
}

结果:两者都想让对方执行完,一直僵持不能往下进行。

七、消费者和生产者

synchronized wait  notify 解决

Object类对线程的支持--》等待和唤醒,wait():进程等待
notify():唤醒一个   notifyAll():唤醒全部
注意:等待按顺序排列,但如果使用notifyAll就看谁的优先权高了

wait时,别人可以访问锁对象,sleep时,别人不可以访问锁对象!!!

public class Info {
	String name = "TOM";
	String content = "飞行员";
	boolean flag = false;
	public synchronized void set(String name,String content){
		if(!flag){
			try {
				super.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		this.name = name;
		try {
			Thread.sleep(300);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		this.content = content;
		flag = false;
		super.notify();
	}
	
	public synchronized void get(){
		if(flag){
			try {
				super.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			try {
				Thread.sleep(300);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		System.out.println(this.getName()+"-->"+this.getContent());
		flag =true;
		super.notify();
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getContent() {
		return content;
	}

	public void setContent(String content) {
		this.content = content;
	}
	
	
	
}
public class Consumer implements Runnable{
	private Info info = null;
	public Consumer(Info info){
		this.info = info;
	}
	
	@Override
	public void run() {
		for(int i = 0;i<50;i++){
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			this.info.get();
		}
		
	}

}
public class Productor implements Runnable{
	private Info info = null;
	public Productor(Info info){
		this.info = info;
	}
	@Override
	public void run() {
		boolean flag = false;
		for(int i=0;i<50;i++){
			if(flag){
				this.info.set("Tom", "飞行员");
				flag = false;
			}else{
				this.info.set("Sam", "宇航员");
				flag = true;
			}
		}
		
	}
}
public class Main {
	public static void main(String[] args) {
		Info info = new Info();
		Productor pro = new Productor(info);
		Consumer con = new Consumer(info);
		new Thread(pro).start();
		new Thread(con).start();
	}
	
}

八、线程的生命周期

suspend():暂时挂起线程
resume():恢复挂起的线程
stop():停止线程
不推荐使用!!!若想停止线程,可以使用标志位

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值