JAVA基础——多线程

来源:互联网 发布:2016淘宝会员名字大全 编辑:程序博客网 时间:2024/06/05 05:00

JAVA基础——多线程

进程:正在进行中的程序,也就是在内存中开辟的一块空间。

线程:负责程序执行的一条路径;
           也称为一个执行单元;
           进程的执行实际上是线程在执行;
            一个进程至少会有一个线程;
           当一个进程中有多个线程程序时,就是多线程程序。
           多线程可以实现不同功能的同时执行,多线程不一定能够提高效率,但是能合理的利用CPU资源。
           多线程最主要的是能实现同时执行的效果。
任务:每个线程需要执行的代码;
          任务代码都有其存储的位置。
            线程是随着任务的存在而存在的,随着任务的结束而消失。


(一)
创建线程的第一种方式:
1.创建一个类继承Thread
2.重写Thread类中的run()方法
3.创建子类对象,其实就是在创建线程
4.启动线程
class Person extends Thread
{
public void run()
{
System.out.println("Hello World!");
}
}
public class Test 
{
public static void main(Strting[] args)
{
Person ren = new Person();//创建一个线程
ren.start();//启动线程
}
}
需要注意:
创建线程是为了执行任务,任务代码必须有存储位置,run()方法就是任务代码的存储位置
当创建了一个线程但没有启动时,程序还是只有两个线程即主线程和立即回收线程
当所有线程全部结束,整个进程才会结束
run()方法只是一个普通的方法调用,不具备启动代码的功能
start()方法会启动线程并执行run()方法中的代码
每个线程在栈中都有一块内存块:
当线程执行完自己的任务代码,线程就从栈中消失,当所有线程都结束了,整个进程才结束
一个线程发生异常,是该线程自己的事,不会影响其他线程的执行。


(二)
创建线程的第二种方式:(常用方式)
1.创建实现了Runnable接口的子类
2.重写Runnable接口中的run()方法
3.创建实现了Runnable接口的子类对象
4.创建Thread类的对象,也就是在创建线程
5.把实现了Runnable接口的子类对象作为参数传递给Thread类的构造函数
第二种创建线程的方式特点是:
把线程任务进行了描述,也就是面向对象。
线程任务和线程对象进行了分离,线程执行什么任务不再重要,只要实现了Runnable接口的子类对象都可以作为参数传递给Thread的构造方法
实现jiekou8de同时还可以继承父类


(三)
线程的安全问题:
操作了共享数据
操作共享数据的代码有多条
出现安全问题的原因:
多条语句被执行了一部分就被抢走了CPU,当线程再次得到CPU时,直接执行后边的语句导致安全问题
解决安全问题的办法:
一个线程得到CPU,执行了多条语句的一部分时,其他线程不能抢走CPU,只有当
     该线程把所有共享数据的语句全部执行完时,其他线程才能抢走CPU


(四)
同步代码块:
java中提供的解决安全问题的方式
synchronized(Object) //获取锁
{  
   操作共享数据的语句  
}     //释放锁
注意:
Object,可以是任意对象,名称为:监视器/锁旗标/锁
锁的作用:实现了排斥其他线程
使用同步代码块,线程每次都要判断锁,降低了程序性能
使用同步代码块需要满足的条件:
1.至少有两个线程
2.使用同一把锁
同步函数:
函数内的代码可以全部放在同步代码块中,那么这个函数就是同步函数
使用synchronized修饰
同步函数的锁是:this
静态同步函数:使用static synchronized修饰的函数
静态同步函数的锁:是其所属类的字节码文件对象  


(五)
线程间的通信:
线程的任务不同,但是线程操作的数据相同
等待唤醒机制:
wait(),使线程进入等待状态,也就是把线程放入等待池
notify()唤醒线程池中的任一线程
notifyAll()唤醒所有线程
wait(),notify(),notifyAll()必须用在同步中,因为只有同步中才有锁
wait(),notify(),notifyAll()为什么定义在Object中?
        因为wait(),notify(),notifyAll()必须用在同步中,因为同步中有锁,锁是任意对象,
       任意对象都可以调用的方法需要定义在Object中。
注意:
        sleep()的线程会持有锁
wait()的线程会放弃锁


(六)
生产者消费者问题:
需要描述生产任务,消费任务,以及描述产品
1.一个生产线程,一个消费线程,不存在安全问题
2.两个生产线程,两个消费线程,会出现生产两次消费一次或者生产一次消费两次的情况
出现问题的原因是:
线程被唤醒之后没有回去判断标记,直接执行后面的代码
解决方式:
让线程被唤醒后不是直接执行后面的代码,而是回去判断标记


(七)
使用jdk1.5之后多线程的实现方式解决一次唤醒所有性能低的问题
jdk1.5之前:
synchronized(Object)
{
    Object.wait();
    Object.notify();
}//操作锁上的线程的方法和锁是绑定在一起的
jdk1.5之后:
Lock lock = new ReentrantLock();
Condition con1 = lock.newCondition();
Condition con2 = lock.newCondition();
lock.lock();
con1.await();
con1.signal();
con2.await();
con2.signal();
lock.unlock();


(八)
线程的停止:
stop()已经过时了,只能当线程的任务代码执行完线程自然结束
1.任务代码通常窦存在循环,所以只要让循环停下来线程就能停下来
2.
Test test = new Test();
Thread th = new Thread(test); 
th.start();
th.interrupt();//线程结束,会抛出InterruptedException


守护线程:
可以看成是后台线程,依赖于前台线程,前台线程全部结束时,即使后台
    线程的代码还没有执行完也会结束。
Test test = new Test();
Thread th1 = new Thread(test);
Thread th2 = new Thread(test);
th1.start();
th2.setDaemonCtrue();
th2.start();
th1.interrupt();
//th1线程结束,th2线程没有结束,但th2设为守护线程,此时也就结束了!
join():加入线程
Test test = new Test();
Thread th1 = new Thread(test);
Thread th2 = new Thread(test);
  1. th1.start();
th1.join();
th2.start();
    //让th1线程加入运行,这时只有主线程和th1线程,所以主线程会等待th1线程全部执行完再执行
    2. th1.start();
th2.start();
th1.join();
   //有主线程,th1,th2线程,只有主线程会等待th1线程执行完,th2不会让着th1


使用匿名内部类创建线程:
第一种方式:
new thread()
{
public void run(){}
}.start();
第二种方式:
new Thread(new Runnable()
{
public void run(){}
}).start();
1 0
原创粉丝点击