通过继承自Thread实现线程
通过继承Thread类自定义一个线程类,并重写run()方法:
//通过继承Thread类实现一个线程
public class MyThread extends Thread {
@Override
public void run() {
Log.d("TAG",Thread.currentThread().getName()+"通过继承实现线程");//打印出当前线程的名称
}
}
实例化一个自定义的线程对象,进行测试:
public void btnClick(View view){
testThread();
}
public void testThread() {
MyThread mt1 = new MyThread();
MyThread mt2 = new MyThread();
//启动线程
mt1.start();
mt2.start();
}
终端输出:
03-28 13:21:18.290 7164-7311/com.example.felix.thread_andorid D/TAG: Thread-156通过继承实现接口
03-28 13:21:18.298 7164-7310/com.example.felix.thread_andorid D/TAG: Thread-155通过继承实现接口
通过实现一个接口实现一个线程
public class MyRunable implements Runnable {
@Override
public void run() {
Log.d("TAG",Thread.currentThread().getName()+"通过接口实现线程");//打印出当前线程的名称
}
}
实例化一个自定义的线程对象,以便进行测试。
public void testRunnable() {
MyRunable mr1 = new MyRunable();
MyRunable mr2 = new MyRunable();
//
Thread th1 = new Thread(mr1);
Thread th2 = new Thread(mr2);
th1.start();
th2.start();
}
终端输出:
03-28 13:29:36.734 13129-13338/com.example.felix.thread_andorid D/TAG: Thread-159通过接口实现线程
03-28 13:29:36.737 13129-13339/com.example.felix.thread_andorid D/TAG: Thread-160通过接口实现线程
多个代理卖火车票实例
public class SaleTicket implements Runnable {
private int ticketNum=20;//火车票总数
@Override
public void run() {
while (true) {
//线程同步
synchronized (this){
if (ticketNum>0){
Log.d("TAG",Thread.currentThread().getName()+"剩余火车票"+ticketNum+"张");
ticketNum--;
}
else {
break;
}
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
定义测试方法:
public void saleTicket(){
SaleTicket saleTicket = new SaleTicket();
//多个线程操作同一个目标对象
Thread tr1 = new Thread(saleTicket,"A代理");
Thread tr2 = new Thread(saleTicket,"B代理");
Thread tr3 = new Thread(saleTicket,"C代理");
Thread tr4 = new Thread(saleTicket,"D代理");
tr1.start();
tr2.start();
tr3.start();
tr4.start();
}
终端输出:
03-28 13:47:42.390 24262-24442/com.example.felix.thread_andorid D/TAG: D代理剩余火车票6张
03-28 13:47:42.404 24262-24441/com.example.felix.thread_andorid D/TAG: C代理剩余火车票5张
03-28 13:47:42.590 24262-24442/com.example.felix.thread_andorid D/TAG: D代理剩余火车票4张
03-28 13:47:42.594 24262-24440/com.example.felix.thread_andorid D/TAG: B代理剩余火车票3张
03-28 13:47:42.594 24262-24439/com.example.felix.thread_andorid D/TAG: A代理剩余火车票2张
03-28 13:47:42.606 24262-24441/com.example.felix.thread_andorid D/TAG: C代理剩余火车票1张
通过继承Thread类实现和通过实现Runnabel接口的区别:
- java属于单继承,存在一定的局限性;
- Runnbale接口适合于资源共享;
线程池的应用
线程池的好处:
- 重用存在的线程,减少对象创建,消亡的开销,性能较好;
- 可有效控制最大并发线程数,提高系统资源的使用率。同时避免过多资源竞争,避免浪费;
- 提供定时执行,定期执行,单线程、并发数控制等功能。
Java四种线程池
-
newCachedThreadPool:可缓存线程池,如果线程长度超过处理需要,可灵活回收空闲线程,若无可回收线程则创建一个新的线程;
public void testCachThreadPool(){ ExecutorService executorService = Executors.newCachedThreadPool(); //实现10个并发的任务 for (int i = 0; i < 10; i++) { final int index = i; executorService.execute(new Runnable() { @Override public void run() { Log.d("TAG",Thread.currentThread().getName()+" ---当前线程 "+index); } }); } }
终端输出:
03-28 14:09:43.623 1126-2831/com.example.felix.thread_andorid D/TAG: pool-2-thread-1 ---当前线程 0
03-28 14:09:43.637 1126-2831/com.example.felix.thread_andorid D/TAG: pool-2-thread-1 ---当前线程 3
03-28 14:09:43.649 1126-2831/com.example.felix.thread_andorid D/TAG: pool-2-thread-1 ---当前线程 6
03-28 14:09:43.657 1126-2831/com.example.felix.thread_andorid D/TAG: pool-2-thread-1 ---当前线程 8
03-28 14:09:43.664 1126-2837/com.example.felix.thread_andorid D/TAG: pool-2-thread-6 ---当前线程 7
03-28 14:09:43.665 1126-2832/com.example.felix.thread_andorid D/TAG: pool-2-thread-2 ---当前线程 1
03-28 14:09:43.666 1126-2836/com.example.felix.thread_andorid D/TAG: pool-2-thread-5 ---当前线程 5
03-28 14:09:43.673 1126-2835/com.example.felix.thread_andorid D/TAG: pool-2-thread-4 ---当前线程 4
03-28 14:09:43.679 1126-2833/com.example.felix.thread_andorid D/TAG: pool-2-thread-3 ---当前线程 2
03-28 14:09:43.682 1126-2838/com.example.felix.thread_andorid D/TAG: pool-2-thread-7 ---当前线程 9
修改代码:
public void testCachThreadPool(){
ExecutorService executorService = Executors.newCachedThreadPool();
//实现10个并发的任务
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(2000);//每执行一次任务休息两秒
} catch (InterruptedException e) {
e.printStackTrace();
}
final int index = i;
executorService.execute(new Runnable() {
@Override
public void run() {
Log.d("TAG",Thread.currentThread().getName()+" ---当前线程 "+index);
}
});
}
}
终端输出:
03-28 14:15:41.549 1126-7361/com.example.felix.thread_andorid D/TAG: pool-3-thread-1 ---当前线程 0
03-28 14:15:43.550 1126-7361/com.example.felix.thread_andorid D/TAG: pool-3-thread-1 ---当前线程 1
03-28 14:15:45.551 1126-7361/com.example.felix.thread_andorid D/TAG: pool-3-thread-1 ---当前线程 2
03-28 14:15:47.553 1126-7361/com.example.felix.thread_andorid D/TAG: pool-3-thread-1 ---当前线程 3
03-28 14:15:49.556 1126-7361/com.example.felix.thread_andorid D/TAG: pool-3-thread-1 ---当前线程 4
03-28 14:15:51.561 1126-7361/com.example.felix.thread_andorid D/TAG: pool-3-thread-1 ---当前线程 5
03-28 14:15:53.562 1126-7361/com.example.felix.thread_andorid D/TAG: pool-3-thread-1 ---当前线程 6
03-28 14:15:55.564 1126-7361/com.example.felix.thread_andorid D/TAG: pool-3-thread-1 ---当前线程 7
03-28 14:15:57.565 1126-7361/com.example.felix.thread_andorid D/TAG: pool-3-thread-1 ---当前线程 8
03-28 14:15:59.566 1126-7361/com.example.felix.thread_andorid D/TAG: pool-3-thread-1 ---当前线程 9
当前我们让每执行一次任务休息两秒后,我们发现10次并发任务的执行过程中只使用了一个线程。这是因为newCachedThreadPool能够回收空闲的线程。
-
newFixedThreadPool: 创建一个定长的线程池,可控制线程的最大并发数,超出的线程会在队列中等待。
public void testFixedThreadPool() { ExecutorService executorService = Executors.newFixedThreadPool(3); for (int i = 0; i < 10; i++) { final int index = i; executorService.execute(new Runnable() { @Override public void run() { Log.d("TAG",Thread.currentThread().getName()+" ---当前线程 "+index); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } }); } }
终端输出:
03-28 14:25:26.900 11037-12323/com.example.felix.thread_andorid D/TAG: pool-2-thread-3 ---当前线程 2
03-28 14:25:26.933 11037-12321/com.example.felix.thread_andorid D/TAG: pool-2-thread-1 ---当前线程 0
03-28 14:25:26.934 11037-12322/com.example.felix.thread_andorid D/TAG: pool-2-thread-2 ---当前线程 1
03-28 14:25:28.902 11037-12323/com.example.felix.thread_andorid D/TAG: pool-2-thread-3 ---当前线程 3
03-28 14:25:28.935 11037-12321/com.example.felix.thread_andorid D/TAG: pool-2-thread-1 ---当前线程 4
03-28 14:25:28.935 11037-12322/com.example.felix.thread_andorid D/TAG: pool-2-thread-2 ---当前线程 5
03-28 14:25:30.903 11037-12323/com.example.felix.thread_andorid D/TAG: pool-2-thread-3 ---当前线程 6
03-28 14:25:30.936 11037-12322/com.example.felix.thread_andorid D/TAG: pool-2-thread-2 ---当前线程 7
03-28 14:25:30.938 11037-12321/com.example.felix.thread_andorid D/TAG: pool-2-thread-1 ---当前线程 8
03-28 14:25:32.906 11037-12323/com.example.felix.thread_andorid D/TAG: pool-2-thread-3 ---当前线程 9
因为最大的线程数被设置为3,所以是每隔两秒执行三个任务。直观的表现是,终端每个两秒打印出三条语句。
- newsingalThreadExecutor:创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证任务按照指定顺序(FIFO,LIFO,优先级)执行。
public void testSingalThread(){
ExecutorService executorService = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
final int index = i;
executorService.execute(new Runnable() {
@Override
public void run() {
Log.d("TAG",Thread.currentThread().getName()+" ---当前线程 "+index);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
程序在运行过程中只会只用一个线程来执行10个任务。
- newScheduledThreadPool:创建一个定长线程池,支持定时及周期性任务执行。
public void testScheduledThreadPool(){
Log.d("TAG","testScheduled");
ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
//定时三秒以后执行
/*schedule()方法:
* 第一个参数:执行的线程任务;
* 第二个参数:时间量;
* 第三个参数:时间量的单位。
* */
scheduledExecutorService.schedule(new Runnable() {
@Override
public void run() {
Log.d("TAG","delay 3 seconds");
}
},3, TimeUnit.SECONDS);
}
终端输出:
03-28 15:09:21.169 23078-23078/com.example.felix.thread_andorid D/TAG: testScheduled
03-28 15:09:24.172 23078-23224/com.example.felix.thread_andorid D/TAG: delay 3 seconds
周期性定时执行任务
/*周期性的定时执行*/
//定时两秒后执行,每个三秒再执行一次
scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
Log.d("TAG","delay 3 seconds");
}
},2,3,TimeUnit.SECONDS);
scheduledExecutorService.shutdown();//关闭周期性执行任务
终端输出:
03-28 15:23:22.607 23078-23078/com.example.felix.thread_andorid D/TAG: testScheduled
03-28 15:23:24.609 23078-28404/com.example.felix.thread_andorid D/TAG: delay 3 seconds
03-28 15:23:27.610 23078-28404/com.example.felix.thread_andorid D/TAG: delay 3 seconds
03-28 15:23:30.609 23078-28404/com.example.felix.thread_andorid D/TAG: delay 3 seconds
03-28 15:23:33.609 23078-28404/com.example.felix.thread_andorid D/TAG: delay 3 seconds
仔细观察每条输出语句的时间。