Java多线程(一)
线程与进程
1、线程:进程中负责程序执行的执行单元,线程本身依靠程序进行运行,线程是程序中的顺序控制流,只能使用分配给程序的资源和环境;
2、进程:执行中的程序,一个进程至少包含一个线程;
3、单线程:程序中只存在一个线程,实际上主方法就是一个主线程;
4、多线程:在一个程序中运行多个任务,目的是更好地使用CPU资源。
线程的实现
Java中有两种方法实现多线程:1、继承Thread类 2、实现 Runnable 接口
一、继承Thread类
Thread 类最重要的方法是 run(),它为Thread 类的方法 start() 所调用,提供我们的线程所要执行的代码。我们在创建Thread 类的子类中重写 run() ,加入线程所要执行的代码即可。
1 public class MyThread extends Thread { 2 3 int count = 1; 4 int number; 5 6 public MyThread(int num) { 7 this.number = num; 8 System.out.println("创建线程 " + number); 9 } 10 11 @Override 12 public void run() { 13 while(true) { 14 System.out.println("线程 " + number + ": 计数" + count); 15 if(++count == 3) { 16 return; 17 } 18 } 19 } 20 21 public static void main(String[] args) { 22 for(int i=0; i<3; i++) { 23 new MyThread(i+1).start(); 24 } 25 } 26 27 }
输出结果:
创建线程 1
创建线程 2
创建线程 3
线程 1: 计数1
线程 3: 计数1
线程 2: 计数1
线程 3: 计数2
线程 1: 计数2
线程 2: 计数2
二、实现 Runnable 接口
Runnable 接口只有一个方法 run(),我们声明自己的类实现 Runnable 接口并提供这一方法,将我们的线程代码写入其中,就完成了这一部分的任务。
但是 Runnable 接口并没有任何对线程的支持,我们还必须创建 Thread 类的实例,这一点通过 Thread 类的构造函数public Thread(Runnable target)来实现。
1 public class MyRunnable implements Runnable{ 2 3 int count = 1; 4 int number; 5 6 public MyRunnable(int num) { 7 this.number = num; 8 System.out.println("创建线程 " + number); 9 } 10 11 @Override 12 public void run() { 13 while(true) { 14 System.out.println("线程 " + number + ": 计数" + count); 15 if(++count == 3) { 16 return; 17 } 18 } 19 } 20 21 public static void main(String[] args) { 22 for(int i=0; i<4; i++) { 23 new Thread(new MyRunnable(i+1)).start(); 24 } 25 } 26 }
输出结果:
创建线程 1
创建线程 2
线程 1: 计数1
线程 1: 计数2
创建线程 3
线程 2: 计数1
线程 2: 计数2
创建线程 4
线程 3: 计数1
线程 3: 计数2
线程 4: 计数1
线程 4: 计数2
实现Runnable接口相对于继承Thread类的优点
1、适合多个相同程序代码的线程去处理同一个资源
2、可以避免由于Java的单继承性带来的局限性
3、增强了程序的健壮性,代码能够被多个线程共享,代码与数据是独立的。
下面通过实现简单的卖票场景来印证上述问题:
1 public class Tickets implements Runnable{ 2 3 private int ticket = 10; 4 5 @Override 6 public void run() { 7 for(int i=0; i<100; i++) { //定义一个超过票数的循环 8 if(ticket>0) { 9 System.out.println(Thread.currentThread().getName() + " sale:" + ticket--); //显示余票 10 } 11 } 12 } 13 14 /* 15 * 如果实例化两个对象,比如实例化ticket1再实例化一个ticket2你会发现两个不同的线程没有共享ticket 16 * 但是如果MyThread是继承Thread类而不是实现接口Runnable,下面的代码将报错。 17 * */ 18 public static void main(String[] args) { 19 Tickets ticket = new Tickets(); 20 Thread t1 = new Thread(ticket); 21 Thread t2 = new Thread(ticket); 22 Thread t3 = new Thread(ticket); 23 Thread t4 = new Thread(ticket); 24 t1.start(); 25 t2.start(); 26 t3.start(); 27 t4.start(); 28 } 29 30 }
输出结果:
Thread-0 sale:10
Thread-3 sale:8
Thread-2 sale:9
Thread-2 sale:4
Thread-2 sale:3
Thread-2 sale:2
Thread-2 sale:1
Thread-3 sale:5
Thread-1 sale:6
Thread-0 sale:7
1 public class Tickets extends Thread { 2 3 private int ticket = 10; 4 5 @Override 6 public void run() { 7 for(int i=0; i<100; i++) { //定义一个超过票数的循环 8 if(ticket>0) { 9 System.out.println(Thread.currentThread().getName() + " sale:" + ticket--); //显示余票 10 } 11 } 12 } 13 14 /* 15 * 如果实例化两个对象,比如实例化ticket1再实例化一个ticket2你会发现两个不同的线程没有共享ticket 16 * 但是如果MyThread是继承Thread类而不是实现接口Runnable,下面的代码将报错。 17 * */ 18 public static void main(String[] args) { 19 Tickets ticket1 = new Tickets(); 20 Tickets ticket2 = new Tickets(); 21 ticket1.start(); 22 // ticket1.start(); //如果同时启动两个ticket1的线程,会报错 23 ticket2.start(); 24 } 25 }
输出结果:
Thread-1 sale:10
Thread-0 sale:10
Thread-1 sale:9
Thread-0 sale:9
Thread-1 sale:8
Thread-0 sale:8
Thread-1 sale:7
Thread-0 sale:7
Thread-1 sale:6
Thread-0 sale:6
Thread-1 sale:5
Thread-0 sale:5
Thread-1 sale:4
Thread-0 sale:4
Thread-1 sale:3
Thread-0 sale:3
Thread-0 sale:2
Thread-1 sale:2
Thread-0 sale:1
Thread-1 sale:1