线程:一个正在执行的程序。 多线程存在的意义: 程序运行中至少有两个线程在运行,一个是主函数的主线程,另一个是垃圾回收的线程。 线程创建方式一: 继承Thread类.要覆盖其run方法,调用线程的start方法. 作用:1.启动线程 2.运行run方法。目的是将自定义的代码存储在run方法中,让线程运行 cpu每次只执行一个程序,只是在快速的不同线程间切换,表现了多线程的随机性 class demo extends Thread{ public void run(){ } } run方法用于存储线程要运行的代码。 demo demo=new demo();创建对象就创建了一个线程。 run方法和 start方法 run方法 仅仅是对象调用方法,并没有运行线程 start方法 是开启线程并且执行线程中的run方法
线程都有自己默认的名称: 获取线程名称的方法。Thread.currentThread().getName() currentThread() 获取当前线程对象 getName() 获取线程名称 设置线程名称 SetName(); 或者构造方法传参
创建线程的第二种方式:实现Runnable接口。 创建线程 Thread t=new Thread(new 对象名()); 步骤: 1,定义类实现Runnable接口。 2,覆盖接口中的run方法(用于封装线程要运行的代码)。 3,通过Thread类创建线程对象; 4,将实现了Runnable接口的子类对象作为实际参数传递给Thread类中的构造函数。 为什么要传递呢?因为要让线程对象明确要运行的run方法所属的对象。 5,调用Thread对象的start方法。开启线程,并运行Runnable接口子类中的run方法。 Ticket t=new Ticket(); /* 直接创建Ticket对象,并不是创建线程对象。 因为创建对象只能通过new Thread类,或者new Thread类的子类才可以。所以最终想要创建线程。既然没有了Thread类的子类,就只能用Thread类。 Thread t1=new Thread(t);//创建线程。 只要将t作为Thread类的构造函数的实际参数传入即可完成线程对象和t之间的关联 实现方式和继承方式有什么区别? 继承Thread类:线程代码块存放在Thread子类的run方法中 实现Runnable,线程代码存放在接口的子类的run方法中,可以被多实现。 继承方式有局限性。要被实现多线程的一个类 如果继承了父类 就不能再继承Thread类。
多线程安全: 安全产生的原因:当多条语句在操作同一个共享数据时,一个线程对多条语句只执行了一部分,还没有执行完, 另一个线程参与进来执行。导致共享数据的错误。 解决办法: 对多条操作共享数据的语句,只能让一个线程都执行完。在执行过程中,其他线程不可以参与执行。 方式:同步代码块: synchronized(对象),火车卫生间案例 { 需要被同步的代码。(共享数据) } 对象如同锁,持有锁的线程可以在同步中执行,没有持有锁的线程,即使获取cpu的执行权,也进不去,因为没有获取锁。 同步的前提: 1.必须要有两个或者两个以上的线程 2.必须多个线程必须使用同一个锁。 必须保证同步中只能有一个线程在运行。 好处:解决了线程的安全问题 弊端:消耗了资源,多个线程需要判断锁。
线程间通信:多个线程在操作同一个资源,但是操作的动作不同。 1.是不是两个或两个以上的线程。解决办法 两个线程都要被同步。 2.是不是同一个锁。解决办法 找同一个对象作为锁。 等待唤醒机制。 wait后,线程就会存在线程池中,notify后就会将线程池中的线程唤醒。 notifyAll();唤醒线程池中所有的线程。 实现方法 : 给资源加个标记 flag synchronized(r) { while(r.flag)//多个生产者和消费者 if(r.flag)//一个生产者和消费者 r.wait(); 代码 r.flag=true; r.notify(); r.notifyAll(); } 上面三种方法都使用在同步中,因为要对持有监视器(锁)的线程操作。所以要使用在同步中,因为只有同步才具有锁。 为什么这些操作线程的方法要定义在object类中呢? 因为这些方法在操作同步中线程的是偶,都必须要表示它们所操作线程只有的锁。只有同一个锁上的被等待线程,可以被 同一个锁上的notify唤醒,不可以对不同锁中的线程进行唤醒。 也就是说,等待和唤醒必须是同一个锁,而锁可以是特意对象,可以被任意对象调用的方法定义在Object类中。