多线程的实现
Java是为数不多的可以支持多线程的编程语言,提供了三种实现多线程的方式(JDK1.5之后提供第三种)
- 继承Thread类
- 实现Runnable接口
- 实现Callable接口
继承Thread类
继承Thread类,重写从Thread类中继承到的run方法
class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(i);
}
}
}
调用start()方法启动线程
MyThread mt1 = new MyThread();
MyThread mt2 = new MyThread();
mt1.start();
mt2.start();
线程的命名和取得
命名
public Thread(String name)
:使用构造方法进行命名setName(String name)
:使用set方法
获取线程的名称
String getName()
:使用get方法
例子:
class MyThread extends Thread {
public MyThread(String name) {
super(name);
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(getName()+":"+i);
}
}
}
MyThread mt1 = new MyThread("线程A");
MyThread mt2 = new MyThread("线程B");
MyThread mt3 = new MyThread("线程C");
//mt1.setName("线程1");
//mt2.setName("线程2");
mt1.start();
mt2.start();
mt3.start();
实现Runnable接口
由于Java中类的单继承性,所有一般实现多线程很少会采用继承Thread类的方式,而是实现Runnable接口来实现多线程
获取当前线程对象
Thread类中提供有一个方法可以获取到当前正在执行的线程对象
Thread currentThread()
线程类
class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
//获取当前线程对象
Thread currentThread = Thread.currentThread();
System.out.println(currentThread.getName() + ":" + i);
}
}
}
启动
MyRunnable mr = new MyRunnable();
Thread t1 = new Thread(mr,"线程A");
Thread t2 = new Thread(mr,"线程B");
t1.start();
t2.start();
线程之间共享数据
模拟多个窗口同时售票,一共有10张票
第一种方法
继承Thread类
class TicketThread extends Thread {
public TicketThread(String name) {
super(name);
}
private int ticket = 10;// 默认10张票
@Override
public void run() {
for (int i = 0; i < 20; i++) {
if(ticket > 0) {
System.out.println(getName()+"卖出了第"+ticket--+"张票!");
}
}
}
}
启动以上线程类,发现不能完成数据的共享,并不是一个10张票,而是每个窗口有10张票
第二种方法
实现Runnable接口
class TicketThread implements Runnable{
private int ticket = 10;//默认只有10张票
@Override
public void run() {
for(int i = 0; i < 20; i++) {
//1.判断剩余票数
if(ticket > 0) {
System.out.println(Thread.currentThread().getName()+"卖出了第"+ticket--+"张票!");
}
}
}
}
使用以上方式,可以实现多个线程之间的数据共享,但是还存在问题,可能卖出重复的票,可能卖出第0张票,甚至负数张票
线程的休眠
void sleep(long millis) throws InterruptedException
例子
@Override
public void run() {
for(int i = 0; i < 10; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
sleep方法可以将线程本身的问题暴露的更明显
线程的优先级
线程一旦启动由CPU决定在什么时间执行那个线程,我们可以手动的设置线程的优先级,优先级高的线程有可能先被执行
方法
void setPriority(int newPriority)
优先级
- 最高:
MAX_PRIORITY
- 中等:
NORM_PRIORITY
- 最低:
MIN_PRIORITY
例子
MyThread myThread = new MyThread();
Thread t1 = new Thread(myThread, "线程1");
Thread t2 = new Thread(myThread, "线程2");
Thread t3 = new Thread(myThread, "线程3");
//设置线程的优先级
t1.setPriority(Thread.MAX_PRIORITY);
t2.setPriority(Thread.NORM_PRIORITY);
t3.setPriority(Thread.MIN_PRIORITY);
t1.start();
t2.start();
t3.start();
实现Callable接口
在JDK1.5之后加入此接口
线程类
class MyThread implements Callable<String>{
@Override
public String call() throws Exception {
for(int i = 1; i <= 100; i++) {
Thread.sleep(40);
System.out.println(i);
}
return "下载完成";
}
}
启动
MyThread myThread = new MyThread();
FutureTask<String> futureTask = new FutureTask<String>(myThread);
Thread thread = new Thread(futureTask);
thread.start();
//获取返回值
try {
String str = futureTask.get();
System.out.println(str);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}