作一个简略的总结~
一、多线程的两种方式
1.通过继承thread类
class Thread1 extends Thread{
public void run(){}
}
直接通过new Thread1(); 即可通过start()启动线程,调用其run方法
2.实现runnable接口
class Thread2 implements Runnable{
public void run(){}
}
启动线程的步骤 :Thread2 t2 = new Thread2();
Thread thread2 = new Thread(t2);
thread2.start();
一般我们在使用多线程中,通过实现Runnable 接口的方式用的比较多,使用第二种方式有如下好处:
1)类可以实现多个接口,但是继承只能继承一个
2)方便资源共享
- class MyThread implements Runnable{
- private int ticket=10;
- public void run(){
- for(int i=0;i<20;i++){
- if(this.ticket>0){
- System.out.println("卖票:ticket"+this.ticket--);
- }
- }
- }
- }
- package org.demo.runnable;
- public class RunnableTicket {
- public static void main(String[] args) {
- MyThread mt=new MyThread();
- new Thread(mt).start();//同一个mt,但是在Thread中就不可以,如果用同一
- new Thread(mt).start();//个实例化对象mt,就会出现异常
- new Thread(mt).start();
- }
- };
上面的例子可以资源共享,共享票数,如果使用第一种方式,创建了3个线程,他对于票数这个变量是独立的,各卖各的票
二、sleep 登场
有时候我们将一个线程停顿一下,让它过一会在继续执行,相当于我们玩游戏的暂停,这个时候在run方法中调用一个sleep(time),time表示休眠多久
三、对于一些资源一个线程正在访问,另一个线程中间改变了它,这会导致混乱,这个时候我们用同步 synchronized 解决这个问题
可以理解为通过同步这个关键字加锁,一个线程访问的时候,其他线程只能等其访问完,这样就不会出现中途被别人修改问题了
使用synchronized 有几种常见的方法,下面列举两种
1.加在方法上
public synchronized void run(){}
当一个线程访问该方法的时候,其他线程不能访问,但这不是绝对的,如果通过统一对象生成的线程,比如像上面都是通过t2对象 new thread(t2)产生的线程,可以避免同一对象的线程访问,但是如果是不同对象生成的,这个方式不能解决,通过使用static 可以保证一个类的所有不同对象的避免。
2.使用在块上
public void run(){
synchronized(lock){
// content
}
}
四、线程的阻塞
常用的方式 wait() 和 notify() 、 notifyAll() ,使用它们必须在synChronized 里面使用,有synchronized 才有锁,这3个方法需要在有锁的情况下使用,需要注意的是,调用完方法后会释放锁。notify() notifyAll() 负责唤醒线程,但是不是说一唤醒线程,它就退出了,还是要等到把自己后面的操作用完,唤醒的线程才起作用。
比如:
- notifyAll();
- // 注意,notifyAll()以后,并没有退出,而是继续执行直到完成。
- System.out.printfln("123");
这里调用了notifyAll(),不是马上就去执行唤醒的线程了,还是会执行下面的输出语句。
五、线程的销毁
线程在完成他的任务后,如果没有其他地方的引用,它会自行销毁。
通过interrupt() stop() suspend() 可以中断线程,但是都不推荐使用
stop() 它会解除由线程获取的所有锁定,而且如果对象处于一种不连贯状态,那么其他线程能在那种状态下检查和修改他们。结果很难检查出真正的问题所在。suspend()方法容易发生死锁。调用suspend()方法的时候,目标线程会停下来,但却仍然持有在这之前获得的锁定。此时,其他任何线程都不能访问锁定的资源,除非被“挂起”的线程恢复运行。对任何线程来说,如果它们想恢复目标线程,同时又试图使用任何一个锁定的资源,就会造成死锁。
六、线程的几个概念区别
1. start() run()
start()方法可以启动线程,执行线程的run方法,如果直接调用run方法,则相当于执行了一个普通的方法,按从上到下的顺序执行代码,不存在多线程的概念了
2. sleep() wait()
sleep是线程类(Thread)的方法,导致此线程暂停执行指定时间,给执行机会给其他线程,但是监恐状态依然保持,到时后会自动恢复。调用sleep不会释放对象锁。wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify方法(或notifyAll方法)后本线程才进入对象锁定池准备获得对象锁进入运行状态。