------- <a href="http://www.itheima.com" target="blank">android培训</a>、<a href="http://www.itheima.com" target="blank">java培训</a>、期待与您交流! ----------
多线程: 多执行绪,同时执行
进程:实际上可以理解为程序,但有的程序可以有多个进程,操作系统可以同时运行多个进程,这样的操作多进程操作
线程:程序运行的执行路径(执行绪)
JVM是多线程的
实现多线程的方式如下:
思路一:
1.定义线程类继承Tread并重写方法
2.重写run()方法,在run方法中写要执行的程序
3.创建线程类对象
4.启动线程,自动调用方法(用线程对象引用调用start()方法)
代码实现过程如下:
// 定义线程类继承Tread并重写方法 public class MyThread extends Thread{ // 重写run()方法,在run方法中写要执行的程序 @Override public void run() { super.run(); for (int i = 0; i < 10; i++) { System.out.println(i); } } }
public class Test { // 创建线程类对象 public static void main(String[] args) { MyThread thread1 = new MyThread(); MyThread thread2 = new MyThread(); // 启动线程 thread1.start(); thread2.start(); } }
public class Test { public static void main(String[] args) { // 用匿名内部类的方式创建线程对象 new MyThread().start(); new MyThread().start(); } }每个线程都有优先级,默认优先级都是5(线程优先级是从1到10的整数)
线程加入:public final void join() throws InterruptedException
使用线程加入的线程,理论上其他线程需要等被加入线程执行完毕后再执行
线程礼让:public static void yield()
暂停当前正在执行的线程对象,并执行其他线程
线程中断:public void interrupt()
中断线程的 wait join sleep 相当于唤醒的意思
线程的生命周期:
新建状态:线程被创建,有执行资格
就绪状态:有执行资格,没有cpu使用权
执行状态:有执行资格,有cpu使用权——> 阻塞状态
消亡状态:线程消亡,既没有执行资格,也没有执行权
阻塞状态:sleep()/wait()/IO操作阻塞操作/加锁 ———>就绪状态 唤醒/唤醒/阻塞操作结束/解锁
守护线程:public final void setDaemon()
被守护线程随着守护线程额停止而停止运行
思路二:
1.定义一个类,实现Runnable 接口
2.重写run()方法
3.创建实例对象 在创建线程的对象的时候,传入参数,还可以直接在第二个参数创建名字
4.分配实例对象(创建一个线程对象最为这个线程对象的构造方法参数传入)
5.开启线程
代码实现:
public class MyRunnable implements Runnable { @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println(i); } } }
public class Test { public static void main(String[] args) { // 创建试了对象 MyRunnable myRunnable = new MyRunnable(); // 分配 实例对象 Thread thread1 = new Thread(myRunnable); Thread thread2 = new Thread(myRunnable); // 启动线程 thread1.start(); thread2.start(); } }
public class Test { public static void main(String[] args) { // 使用匿名内部类的方式创建线程对象 new Thread(new MyRunnable(){ @Override public void run() { super.run(); for (int i = 0; i < 10; i++) { System.out.println(i); } } }).start(); // 开启线程 } }
总结:实现runnable接口比继承Thread类好,因为可以在实现接口的同事继承其他的类,而如果继承了Thread类就不能再继承其他的类
这样将run方法中的业务与线程分离
synchronize:同步
使用同步代码块将要同步的代码包裹起来,该代码块需要一个对象作为参数,这个参数是同步代码块的锁由这个锁去判断是否是同一个代码块
锁的创建不能在run()方法内,因为如果放在run方法中,则每个线程都有自己的锁,与其他线程的锁不同,所以锁应该放在成员变量的位置(即在成员位置创建锁的参数对象)
代码实现过程:
1.让共享数据事项runnable接口
2.创建多线程对象,传入相同的共享数据对象
3.开启线程验证
public class Ticket implements Runnable { // 必须要将共享的属性放在成员的位置作为共享数据 int num = 100; Object o = new Object(); @Override public void run() { while (true) { synchronized (o) { //此同步代码块不能包括while循环,因为将导致最先获取执行权线程的死循环 try { Thread.sleep(10); // 让线程睡眠10ms验证数据的同步性 } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } if (num > 0) { System.out.println(Thread.currentThread().getName()+"正在销售第"+num+"张票"); num--; } } } } }测试类:
public class Test { public static void main(String[] args) { // 创建共享 数据的对象 Ticket ticket = new Ticket(); // 创建线程对象 Thread thread = new Thread(ticket,"窗口1"); Thread thread2 = new Thread(ticket,"窗口2"); // 开启线程 thread.start(); thread2.start(); } }
格式:在方法前加 synchronize 关键字
多个线程跑的都是自己的run()方法,但是共享着run方法中的某些数据
总结:多线程可以保证共享数据的唯一性,可以通过让共享数据的放在成员变量的位置,或者只创建共享数据的一个实例对象来保证数据的唯一性
注意:synchronize 同步代码块只能使用同一个对象才能达到同步的功能