1.java创建线程的三种基本方式
- 方式一:继承Thread类创建线程类
public class FirstThreadTest extends Thread{
int i = 0;
//重写run方法,run方法的方法体就是现场执行体
public void run()
{
for(;i<100;i++){
System.out.println(getName()+" "+i);
}
}
public static void main(String[] args)
{
for(int i = 0;i< 100;i++)
{
System.out.println(Thread.currentThread().getName()+" : "+i);
if(i==20)
{
new FirstThreadTest().start();
new FirstThreadTest().start();
}
}
}
}
- 方式二:通过Runnable接口创建线程类
public class RunnableThreadTest implements Runnable
{
private int i;
public void run()
{
for(i = 0;i <100;i++)
{
System.out.println(Thread.currentThread().getName()+" "+i);
}
}
public static void main(String[] args)
{
for(int i = 0;i < 100;i++)
{
System.out.println(Thread.currentThread().getName()+" "+i);
if(i==20)
{
RunnableThreadTest rtt = new RunnableThreadTest();
new Thread(rtt,"新线程1").start();
new Thread(rtt,"新线程2").start();
}
}
}
}
- 方式三:通过Callable和Future创建线程
public interface Callable
{
V call() throws Exception;
}
public class CallableThreadTest implements Callable<Integer>
{
public static void main(String[] args)
{
CallableThreadTest ctt = new CallableThreadTest();
FutureTask<Integer> ft = new FutureTask<>(ctt);
for(int i = 0;i < 100;i++)
{
System.out.println(Thread.currentThread().getName()+" 的循环变量i的值"+i);
if(i==20)
{
new Thread(ft,"有返回值的线程").start();
}
}
try
{
System.out.println("子线程的返回值:"+ft.get());
} catch (InterruptedException e)
{
e.printStackTrace();
} catch (ExecutionException e)
{
e.printStackTrace();
}
}
@Override
public Integer call() throws Exception
{
int i = 0;
for(;i<100;i++)
{
System.out.println(Thread.currentThread().getName()+" "+i);
}
return i;
}
}
创建线程的三种方式的对比
-
使用继承Thread类的方式创建多线程时,
优势是:
编写简单,如果需要访问当前线程,则无需使用Thread.currentThread()方法,直接使用this即可获得当前线程。
劣势是:
线程类已经继承了Thread类,所以不能再继承其他父类。 -
采用实现Runnable、Callable接口的方式创建多线程时,
优势是:
线程类只是实现了Runnable接口或Callable接口,还可以继承其他类。
在这种方式下,多个线程可以共享同一个target对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU、代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想。
劣势是:
编程稍微复杂,如果要访问当前线程,则必须使用Thread.currentThread()方法。 -
Runnable和Callable的区别
(1) Callable规定(重写)的方法是call(),Runnable规定(重写)的方法是run()。
(2) Callable的任务执行后可返回值,而Runnable的任务是不能返回值的。
(3) call方法可以抛出异常,run方法不可以。
(4) 运行Callable任务可以拿到一个Future对象,表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。通过Future对象可以了解任务执行情况,可取消任务的执行,还可获取执行结果。
注意:
- 在程序开发中只要是多线程肯定永远以实现Runnable接口为主,因为实现Runnable接口相比继承Thread类有如下好处:
(1)避免点继承的局限,一个类可以实现多个接口。
(2)适合于资源的共享
2.线程池
- 线程池的引入好处:
1)提升性能。创建和消耗对象费时费CPU资源
2)防止内存过度消耗。控制活动线程的数量,防止并发线程过多
在Android中当同时并发多个网络线程时,引入线程池技术会极大地提高APP的性能。
public class ThreadPoolTest {
static ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
static ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);
static ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
public static void main(String[] args) {
MyTreadPool myTreadPool = new MyTreadPool(5, 10);
for (int i = 0; i < 110; i++) {
myTreadPool.execute(new Runnable() {
@Override
public void run() {
test();
}
});
}
}
static class MyTreadPool{
private ThreadPoolExecutor threadPoolExecutor;
public MyTreadPool(int corePoolSize, int maximumPoolSize){
//corePoolSize 核心线程数
//maximumPoolSize 最大的线程数
//keepAliveTime 大于corePoolSize线程在空闲状态下存活的时间
//unit keepAliveTime的单位
//workQueue 等待队列
//threadFactory 线程工厂
BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(100);
threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, 60L, TimeUnit.SECONDS, workQueue , new ThreadFactory() {
AtomicInteger count = new AtomicInteger();
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r, "MyTreadPool-thread-"+count.incrementAndGet());
return t;
}
});
}
public void execute(Runnable r){
threadPoolExecutor.execute(r);
}
}
public static void test() {
String name = Thread.currentThread().getName();
System.out.println("线程" + name + "进来了");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程" + name + "出来了");
}
}
3.补充
3.1 ThreadFactory
ThreadFactory factory = new ThreadFactory() {
int count = 0;
@Override
public Thread newThread(Runnable r) {
count ++;
return new Thread(r, "Thread-" + count);
}
};
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()
+ " started!");
}
};
Thread thread = factory.newThread(runnable);
thread.start();
Thread thread1 = factory.newThread(runnable);
thread1.start();
3.2 Executor 和线程池
- 常⽤:
newCachedThreadPool()
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("Thread with Runnable started!");
}
};
Executor executor = Executors.newCachedThreadPool();
executor.execute(runnable);
executor.execute(runnable);
executor.execute(runnable);
- 短时批量处理:
newFixedThreadPool()
ExecutorService executor = Executors.newFixedThreadPool(20);
for (Bitmap bitmap : bitmaps) {
executor.execute(bitmapProcessor(bitmap));
}
executor.shutdown();
- Callable 和 Future
Callable<String> callable = new Callable<String>() {
@Override
public String call() {
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Done!";
}
};
ExecutorService executor = Executors.newCachedThreadPool();
Future<String> future = executor.submit(callable);
try {
String result = future.get();
System.out.println("result: " + result);
} catch (InterruptedException | ExecutionException e){
e.printStackTrace();
}