线程技术初窥
1. 程的生命周期(仔细看图) :
2. main线程以及继承Thread实现多线程:
虽然多线程看起来像同时进行,但事实上在同一时间点上只有一个线程被执行,只是线程间切换较快,所以才会使人产生线程是同时进行的假象。
Therad类的currentThread()方法可以获取当前线程并输出该线程的名称。
代码如下:
public class MainThread {
public static void main(String[] args) {
System.out.println("main 主方法开始运行");
Thread currentThread =Thread.currentThread();
System.out.println("获取当前线程对象");
String name =currentThread.getName();
System.out.println("当前线程名称是:"+name);
}
}
建立多线程需要重写run()方法:
public class Writer extends Thread {
private String name;
public Writer(String name) {
this.name = name;
}
public void run() {
while (true) {
System.out.println(name);
try {
Thread.sleep((int)(Math.random()*10000));
} catch (Exception e) {
}
}
}
public static void main(String[] args) {
Thread writer1=new Writer("作者1");
Thread writer2=new Writer("作者2");
writer1.start();
writer2.start();
}
}
public class Writer implements Runnable {
long minPrime;
Writer(long minPrime) {
this.minPrime = minPrime;
}
public void run() {
}
public static void main(String[] args) {
Writer writer1 = new Writer(123);
new Thread(writer1).start();
}
}
3. 线程的休眠:
sleep()方法.
try {
Thread.sleep(2000);
} catch (Exception e) {
}
表示线程在2000毫秒内不会进入就绪状态,也就是暂停两秒。
4. 线程停止:
早期版本里用stop()方法停止线程,但是新版本里废除了stop()方法。现在提倡在run()方法中使用布尔型标记控制循环停止。
例:在项目中创建InterruptedTest类,该类继承了Runnable方法,设置线程正确停止方式。
public class InterruptedTest implements Runnable {
private boolean isContinue = true;
@Override
public void run() {
while (true) {
if (isContinue)
break;
}
}
public void setContinue() {
this.isContinue = true;
}
}
如果线程因为是使用了sleep()或wait()方法进入了就绪状态,可以使用interrupt()方法使线程离开run()方法,同时结束线程,但程序会抛出InterruptedException异常。
5. 线程调度:
当某个线程使用join()方法加入到另一个线程时,另一个线程会等待该线程执行完毕再继续执行。
实例:
import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JProgressBar;
/**
* 线程调度的实例
* @author 李钟尉
*/
public class JoinMain extends JFrame {
private Thread threadA; // 线程A
private Thread threadB; // 线程B
private Thread threadC; // 线程B
final JProgressBar progressBarA = new JProgressBar(); // 进度条A
final JProgressBar progressBarB = new JProgressBar(); // 进度条B
final JProgressBar progressBarC = new JProgressBar(); // 进度条C
public static void main(String[] args) {
new JoinMain();
}
/**
* 构造方法
*/
public JoinMain() {
super();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(200, 100);
setVisible(true);
getContentPane().add(progressBarA, BorderLayout.NORTH);
getContentPane().add(progressBarB);
getContentPane().add(progressBarC, BorderLayout.SOUTH);
progressBarA.setStringPainted(true);
progressBarA.setString("线程A");
progressBarB.setStringPainted(true);
progressBarB.setString("线程B");
progressBarC.setStringPainted(true);
progressBarC.setString("线程C");
// 创建线程A
threadA = new Thread(new Runnable() {
public void run() {
for (int i = 0; i <= 100; i++) {
progressBarA.setValue(i);
progressBarA.setString("线程A " + i + "%");
try {
Thread.sleep(100); // 休眠0.1秒
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
// 创建线程B
threadB = new Thread(new Runnable() {
public void run() {
for (int i = 0; i <= 100; i++) {
progressBarB.setValue(i);
progressBarB.setString("线程B " + i + "%");
try {
Thread.sleep(100);
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
// 创建线程C
threadC = new Thread() {
public void run() {
for (int i = 0; i <= 100; i++) {
progressBarC.setValue(i);
progressBarC.setString("线程C " + i + "%");
try {
Thread.sleep(100);
} catch (Exception e) {
e.printStackTrace();
}
}
}
};
try {
threadA.start(); // 启动线程A
threadA.join();
threadB.start(); // 启动线程B
threadB.join();
threadC.start(); // 启动线程B
threadC.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
6. 设置线程优先级:
Thread 有优先级,比如
MAX_PRIORITY 线程可以具有的最高优先级。
MIN_PRIORITY 线程可以具有的最低优先级。
NORM_PRIORITY 分配给线程的默认优先级。
线程优先级可以通过setPriority()方法调整,优先级必须在1-10之内,否则将产生异常。
7. 线程同步问题:
在多线程编程中,必须防止资源的冲突。Java提供线程同步的机制可以防止资源访问的冲突.
线程的同步机制:
如何解决资源共享问题,通常是允许一个线程访问共享资源,这时就给共享资源加把锁。
1.同步块:
java同步机制中采用synchronized关键字。它的语法结构如下:
synchronized (object) {
//业务代码
}
模拟火车站售票系统:
/**
* 本实例演示多个线程同时访问一个公有资源的安全问题
*/
public class ThreadSafeTest extends Thread {
private static Integer num = 1; // 剩余票数(共享资源)
/**
* 构造方法
* @param name 线程的名称,本实例对应售票员名称
*/
public ThreadSafeTest(String name) {
setName(name); // 设置线程名
}
/**
* 线程核心方法
*/
@Override
public void run() {
synchronized (num) {
if (num > 0) { // 检查剩余票数
System.out.println(getName() + ":检测票数大于0");
System.out.println(getName() + ":\t正在收款(大约5秒完成)……");
try {
Thread.sleep(5000); // 5秒收款时间
System.out.println(getName() + ":\t打印票据,售票完成");
num--;
printNumInfo(); // 输出车票状况信息
} catch (InterruptedException e) {
e.printStackTrace();
}
}
else {
System.out.println("没有票了,停止出售");
}
}
}
/**
* 输出车票状况信息的方法,该方法输出当前剩余票数,如果低于0则输出经过信息
*/
private void printNumInfo() {
System.out.println("系统:当前剩余票数:" + num);
if(num<0){ // 如果剩余票数呈现负数
System.out.println("警告:票数低于0,出现负数");
}
}
/**
* @param args
*/
public static void main(String[] args) {
try {
new ThreadSafeTest("售票员李某").start(); // 启动第一个线程
Thread.sleep(2000); // 两秒后
new ThreadSafeTest("售票员王某").start(); // 启动第二个线程
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
同步方法是在方法前面修饰synchronized关键字的方法,它的语法如下
synchronized void syncMethod() {
//业务代码
}
当某个对象调用同步方法时,其它方法必须等待该同步方法执行完毕才能被执行。所有将每个能访问共享资源的方法修饰为synchronized可以防止多个线程同时修改或访问共享资源。
还是上面的例子:
public class ThreadSafeTest extends Thread {
private static int num = 1; // 剩余票数
/**
* 构造方法
* @param name 线程的名称,本实例对应售票员名称
*/
public ThreadSafeTest(String name) {
setName(name); // 设置线程名称
}
/**
* 线程核心方法
*/
@Override
public void run() {
sell(getName()); // 执行售票方法
}
/**
* 销售车票的方法,该方法是线程安全的。
* @param name 售票员名称
*/
private static synchronized void sell(String name) {
System.out.println(name+":开始售票,正在查询票数……");
if (num > 0) {
System.out.println(name + ":检测票数大于0");
System.out.println(name + ":\t正在收款(大约5秒完成)……");
try {
Thread.sleep(5000);
System.out.println(name + ":\t打印票据,售票完成");
num--;
printNumInfo();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else{
System.out.println(name + ":\t没有票了,停止出售");
}
}
/**
* 输出车票库存情况的方法,如果库存为负数,输出警告信息
*/
private static void printNumInfo() {
System.out.println("系统:当前剩余票数:" + num);
if(num<0){
System.out.println("警告:票数低于0,出现负数");
}
}
/**
* @param args
*/
public static void main(String[] args) {
try {
new ThreadSafeTest("售票员李某").start();
Thread.sleep(2000);
new ThreadSafeTest("售票员王某").start();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}