1、什么是线程?与进程的关系?
进程:内存中的一个运行程序。
线程:进程中的一个执行任务,负责当前进程中程序的执行,一个进程中至少有一个线程;与进程不同的是同类的线程共享进程中的堆和方法区资源,但每个线程都有自己的程序计数器、虚拟机栈、本地方法栈。
一个进程中至少有一个线程,一个进程可以运行多个线程。
2、创建线程的四种方式
有的地方可能说只有两种:①继承自Thread ②实现Runnable接口
直接使用对象.run()同方法调用
继承Thread类
继承Thread类需要重写run方法
class MyThread extends Thread {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"向你问好!");
}
}
public class Demo1 {
public static void main(String[] args) {
MyThread[] mt = new MyThread[20];
for(int i = 0;i < 20;i++) {
mt[i] = new MyThread();
mt[i].start();
}
}
}
实现Runnable接口
假设Runnable接口的实现类是A,创建A的实例a后,此时的a还并不是一个线程,需要用它来实例化一个Thread类才能作为一个线程跑起来
Demo3类实现Runnable接口
package cn.com.pool;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.swing.JLabel;
public class Demo3 extends JLabel implements Runnable{
private Date t;
private int time;
private boolean judge;
private SimpleDateFormat sdf;
@Override
public void run() {
while(judge) {
try {
t = new Date();
this.setText(sdf.format(t));
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public boolean isJudge() {
return judge;
}
public void setJudge(boolean judge) {
this.judge = judge;
}
public Demo3(int time) {
judge = true;
this.time = time;
this.sdf = new SimpleDateFormat("HH-mm-ss");
}
}
测试类Demo4
package cn.com.pool;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Demo4 extends JFrame{
private Demo3 lbl1;
private Demo3 lbl2;
private Demo3 lbl3;
private JButton btn1;
private JButton btn2;
private JPanel jpanel;
public Demo4() {
lbl1 = new Demo3(1000);
lbl2 = new Demo3(3000);
lbl3 = new Demo3(5000);
btn1 = new JButton("开始");
btn2 = new JButton("暂停");
this.jpanel = new JPanel(null);
this.setSize(500, 400);
this.jpanel.setSize(500, 400);
init();
}
private void init() {
lbl1.setBounds(150, 100, 120, 30);
lbl2.setBounds(150, 150, 120, 30);
lbl3.setBounds(150, 200, 120, 30);
btn1.setBounds(150, 250, 70, 30);
btn2.setBounds(220, 250, 70, 30);
//将Demo3类的实例包装成一个线程
Thread t1 = new Thread(lbl1);
Thread t2 = new Thread(lbl2);
Thread t3 = new Thread(lbl3);
btn1.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
start();
}
});
btn2.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
stop();
}
});
jpanel.add(lbl1);
jpanel.add(lbl2);
jpanel.add(lbl3);
jpanel.add(btn1);
jpanel.add(btn2);
t1.start();
t2.start();
t3.start();
this.add(jpanel);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
private void stop() {
lbl1.setJudge(false);
lbl2.setJudge(false);
lbl3.setJudge(false);
}
private void start() {
lbl1.setJudge(true);
lbl2.setJudge(true);
lbl3.setJudge(true);
Thread t1 = new Thread(lbl1);
Thread t2 = new Thread(lbl2);
Thread t3 = new Thread(lbl3);
t1.start();
t2.start();
t3.start();
}
public static void main(String[] args) {
new Demo4();
}
}
实现Callable接口
继承Thread类和实现Callable接口这两种方法创建线程时,重写的run方法没有返回值、也无法throws异常;而实现Callable接口,重写的run方法有返回值而且还能throws异常 --- throws的异常由JVM虚拟机捕获处理,而run方法返回的结果则在FutureTask中,通过FutureTask实现类中的get方法来获取
注意:想要有结果必须用它来实例化一个Thread类,而且FutureTask也是Runnable、Callable的实现类
/**
* 输出0~TIMES间的偶数
*/
class EvenThread implements Callable {
@Override
public Object call() throws Exception {
for (int i = 0; i < CreateDemo4.TIMES; i++) {
if (i % 2 == 0) {
System.out.println(Thread.currentThread().getName() + ": " + i + " 次");
}
}
return 3;
}
}
/**
* 测试实现Callable接口的方式创建线程
*/
public static void demo3Test() {
CreateDemo3 thread1 = new CreateDemo3("Thread1");
FutureTask task1 = new FutureTask(thread1);
new Thread(task1).start();
try {
System.out.println(task1.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
通过线程池创建线程
/**
* 使用线程池创建线程
*/
public void createThread() {
ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
//适合Runnable
executor.execute(new OddThread());
/*//适合Callable
executorService.submit();*/
executor.shutdown();
}