多线程(多线程的引入)
线程 :
* 线程是程序执行的一条路径,一个进程中可以包含多条线程。
* 多线程并发执行可以提高程序的效率,可以同时完成多项工作。
应用场景:
* 服务器同时处理多个客户端请求。
多线程(多线程并行和并发的区别)
* 并行就是两个任务同时运行,就是甲任务进行的同时,乙任务也在运行。( 需要多个cpu)
* 并发是指两个任务都请求运行,而处理器只能接收一个任务,就把这两个任务安排轮流进行,由于时间间隔较短,使人感觉两个任务都在运行。
多线程(多线程程序实现的方式 )
* extends Thread:
public class Dome1_Thread { public static void main(String[] args) { // MyThread my=new MyThread(); //4.创建MyThread子类对象 my.start(); //5.statr()开启线程 for (int i = 0; i <10; i++) { System.out.println("b"); } } } class MyThread extends Thread{ //1.继承Thread public void run() { //2.重写run() for (int i = 0; i < 10; i++) { //3.将要执行的代码放在run()中 System.out.println("aaa"); } for (int i = 0; i < 10; i++) { //将要执行的代码放在run()中 System.out.println("ccc"); } } }
* implements Runnable:
public class Dome1_Thread { public static void main(String[] args) { // MyRunnable mr = new MyRunnable(); //4.创建Runnable的子类对象 Thread t = new Thread(mr); //5.将其当作参数传递给Thread的构造函数 t.start(); //6.开启线程 for (int i = 0; i < 10; i++) { System.out.println("b"); } } } class MyRunnable implements Runnable{ //1.定义一个类实现Runnable @Override public void run() { //2.重写run() for (int i = 0; i < 10; i++) { //3.将要执行的代码放在run()中 System.out.println("aaa"); } } }
两种方式的区别:
* 继承Thread
* 好处是:可以直接使用Thread类中的方法,代码简单。
* 弊端是:如果已经有了父类,就不能用这种方法。
* 实现Runnable接口:
* 好处是:即使自己定义的线程类有了父类也没关系,因为父类也可以实现接口,而且接口是可以多实现的。
* 弊端是:不能直接使用Thread中的方法需要先获取线程对象后才能得到Thread的方法。
多线程(匿名内部类实现线程)
public static void main(String[] args) { //方法1: new Thread() { // 1.继承Thread() public void run() { // 2.重写run() for (int i = 0; i <= 10; i++) { // 3.将要执行的代码放在run()中 System.out.println("aaa"); } } }.start(); // 4.statr()开启线程 //方法2: new Thread( new Runnable() { //1.将Runnable的子类对象传递给Thread的构造方法 public void run() { // 2.重写run() for (int i = 0; i <= 10; i++) { // 3.将要执行的代码放在run()中 System.out.println("bbb"); } } }).start(); // 4.statr()开启线程 }
多线程(获取当前线程的对象)
* Thread.currentThread() :获取当前正在执行的线程。
public static void main(String[] args) { new Thread() { public void run() { System.out.println(this.getName() + "...aaa"); } }.start(); new Thread( new Runnable() { public void run() { //Thread.currentThread()获取当前正在执行的线程 System.out.println(Thread.currentThread().getName() +"...bbb"); } }).start(); // 设置主线程名字 Thread.currentThread().setName("陈琳狗"); //获取主线程名字 System.out.println(Thread.currentThread().getName()); }
多线程(休眠线程)
* Thread.sleep(毫秒 ,纳秒):控制当前线程休眠若干毫秒
(1秒=1000 毫秒 1秒=1000*1000*1000 纳秒)
多线程(守护线程)
* setDaemon( ) :设置一个线程为守护线程,该线程不会单独执行,当其他非守护线程都执行结束后,自动推出。( 当传入为true就是意味着设置为守护线程。)
多线程(加入线程)
* join( ) :当前线程暂停,等待指定的线程执行结束后,当前线程再继续。
* join( int ) :可以等待指定的毫秒之后继续。
public static void main(String[] args) { final Thread t1 = new Thread() { public void run() { for (int i = 0; i < 10; i++) { System.out.println(getName() + "....aaa"); } } }; Thread t2 = new Thread() { public void run() { for (int i = 0; i < 10; i++) { if (i==2) { try { // t1.join(); t1.join(1); // 插队指定时间,过了指定时间后,两条线程交替执行 } catch (InterruptedException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } } System.out.println(getName() + "....bbbbbb"); } } }; t1.start(); t2.start(); }
多线程(设置线程的优先级)
setPriority (Thread .MIN_PRIORITY);
setPriority (Thread .MAX_PRIORITY);
多线程(同步代码块)
synchronized( ){ } :同步代码块,锁机制,锁对象可以是任意的(锁对象不能用匿名对象,因为匿名对象不是同一个对象)。
使用情况:
* 当多线程并发,有多段代码同时执行时,我们希望某一段代码执行的过程中CPU不要切换到其他线程工作,这时就需要同步。
* 如果两段代码块是同步的,那么同一时间只能执行一段,在一段代码块没执行结束之前,不会执行另外一段代码。
同步代码块:多个同步代码如果使用相同的锁对象,那么他们就是同步的。
public class Dome1_Synchronized { public static void main(String[] args) { final printss p = new printss(); new Thread() { public void run() { while (true) { p.print1(); } } }.start(); new Thread() { public void run() { while (true) { p.print2(); } } }.start(); } } class printss { Dome d=new Dome(); public void print1() { synchronized (d) { //synchronized(){} :同步代码块,锁机制,锁对象可以是任意的(锁对象不能用匿名对象,因为匿名对象不是同一个对象) System.out.print("a"); System.out.print("b"); System.out.print("c"); System.out.println(" "); } } public void print2() { synchronized (d) { System.out.print("e"); System.out.print("f"); System.out.print("g"); System.out.println(" "); } } } class Dome{ }
多线程(同步方法)
同步方法只需要在方法上加synchronized关键字即可。
public synchronized void print1() { //同步方法只需要在方法上加synchronized关键字即可。 System.out.print("a"); System.out.print("b"); System.out.print("c"); System.out.println(" "); } public void print2() { //非静态的同步方法的锁对象是this synchronized (this) { System.out.print("d"); System.out.print("e"); System.out.print("f"); System.out.println(" "); } }
//静态同步方法 class printstatic{ public synchronized void print1() { //同步方法只需要在方法上加synchronized关键字即可。 System.out.print("a"); System.out.print("b"); System.out.print("c"); System.out.println(" "); } public void print2() { synchronized (printstatic.class) { //静态的同步方法的锁对象是该类的字节码对象 System.out.print("d"); System.out.print("e"); System.out.print("f"); System.out.println(" "); } } }
多线程(线程安全问题)
* 多线程并发操作同一数据时,就有可能出现线程安全问题。
* 使用同步技术可以解决这种问题,把操作数据的代码进行同步,不要多个线程一起操作。
public class Dome3_Ticket { public static void main(String[] args) { //需求:卖100张票,四个窗口 new Ticket().start(); new Ticket().start(); new Ticket().start(); new Ticket().start(); } } class Ticket extends Thread{ private static int ticket=100; //增加Static静态使四个线程公用一个ticket // private static Object object=new Object(); //如果用引用数据类型成员变量当作锁对象,必须是静态的。 public void run() { while (true) { synchronized (Ticket.class) { if (ticket<=0) { break; } try { Thread.sleep(10); } catch (InterruptedException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } System.out.println(getName()+"...这是第"+ticket--+"号票"); } } } }
public class Dome_Ticket { public static void main(String[] args) { // Runnable接口实现火车站卖票例子 4个窗口 MyTicket mt= new MyTicket(); new Thread(mt).start(); new Thread(mt).start(); new Thread(mt).start(); new Thread(mt).start(); } } class MyTicket implements Runnable{ private int ticket=100; @Override public void run() { while (true) { synchronized (Ticket.class) { if (ticket<=0) { break; } try { Thread.sleep(10); } catch (InterruptedException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"...这是第"+ticket--+"号票"); } } } }
多线程(死锁)
多线程同步的时候,如果同步代码块嵌套,使用相同的锁,就有可能出现死锁。(尽量不要嵌套使用)