1、Java 线程(Thread)
线程允许程序通过同时执行多项操作来更有效地运行。
线程可用于在后台执行复杂的任务,而不会中断主程序。
2、创建线程Thread
有两种创建线程的方法。
可以通过扩展Thread
类并覆盖其run()
方法来创建它:
使用extends语法
public class Main extends Thread { public void run() { System.out.println("在线程中运行代码"); } }
创建线程的另一种方法是实现Runnable
接口:
使用implement语法
public class Main implements Runnable { public void run() { System.out.println("在线程中运行代码"); } }
3、运行线程
如果该类使用extends
扩展了Thread
类,则可以通过创建该类的实例并调用其start()
方法来运行该线程:
例如:
public class Main extends Thread { public static void main(String[] args) { Main thread = new Main(); thread.start(); System.out.println("thread线程外运行"); } public void run() { System.out.println("thread线程中运行"); } }
如果该类使用implements
实现了Runnable
接口,则可以通过将类的实例传递给Thread
对象的构造函数,然后调用该线程的start()
方法:
例如:
public class Main implements Runnable { public static void main(String[] args) { Main obj = new Main(); Thread thread = new Thread(obj); thread.start(); System.out.println("thread线程外运行"); } public void run() { System.out.println("thread线程中运行"); } }
使用extends
的线程与使用implements
的线程之间的区别主要区别在于,当一个类扩展Thread
类时,不能扩展任何其他类,但是通过实现Runnable
接口,可以从 另一个类,例如:classMyClass
扩展实现了Runnable
接的OtherClass
。
4、线程并发问题
因为线程与程序的其他部分同时运行,所以无法知道代码将以什么顺序运行。当线程和主程序正在读取和写入相同的变量时,这些值是不可预测的。由此产生的问题称为并发问题。
例如:
一个代码示例,其中amount的值不可预测:
public class Main { public static void main(String[] args) { MyThread thread = new MyThread(); thread.start(); // 更新输出值 System.out.println("Main begin: " + MyThread.amount); MyThread.amount++; System.out.println("Main end: " + MyThread.amount); } } class MyThread extends Thread { public static int amount = 0; public void run() { amount++; } }
为避免并发问题,最好在线程之间共享尽可能少的属性。 如果需要共享属性,则一种可能的解决方案是使用线程的isAlive()
方法在使用任何可以更改的属性之前检查线程是否已完成运行。
例如:
使用isAlive()
防止并发问题:
public class Main { public static void main(String[] args) { MyThread thread = new MyThread(); thread.start(); // 等待线程运行完成 while(thread.isAlive()) { System.out.println("Waiting..."); } // 更新输出值 System.out.println("Main begin: " + MyThread.amount); MyThread.amount++; System.out.println("Main end: " + MyThread.amount); } } class MyThread extends Thread { public static int amount = 0; public void run() { amount++; } }
另外还可以加锁的方式,解决并发问题,例如,Java中线程的共享互斥操作,会使用synchronized
关键字。每个锁在同一时刻,只能由一个线程持有。例如,
public class Main { public static void main(String[] args) { MyThread thread = new MyThread(); thread.start(); // 更新并输出值 synchronized (MyThread.class) { System.out.println("Main begin: " + MyThread.amount); MyThread.amount++; System.out.println("Main end: " + MyThread.amount); } } } class MyThread extends Thread { public static int amount = 0; public void run() { synchronized (MyThread.class) { amount++; } } }
注意:synchronized
方法或声明执行期间,如程序遇到任何异常或return
,线程都会释放锁。