1. Thread
2. Runnable
3. Callable
Runnable/Thread 区别
1. Java 不支持多继承, 所以实现接口Runnable是一个比较好的选择.
2. 从设计的角度看,实现子类通常意味着添加或者修改一些功能, 而实现接口则表示实现一个统一的动作.所以一般情况实现Runnable较好.
3. Runnable接口代表了一个Task, 可以被Thread/Executors来调用, 从这点来说将一个Task作为Runnable来实现比较好.
所以如果在Runnable和Thread中取舍, 还是选择Runnable吧.如果应用ExecutorService不要忘记shutdown.
package thread;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.atomic.AtomicInteger;
public class ThreadTest {
public static void main(String args[]) throws Exception{
MyThread mt = new MyThread();
//mt.run(); If we call run like this, the thread is main thread
mt.start();
MyRunnable mr = new MyRunnable();
//mr.run();If we call run like this, the thread is main thread
Thread t = new Thread(mr);
t.start();
MyExecutors.executeThreads();
}
}
class MyThread extends Thread {
public void run(){
System.out.println("This is MyThread ");
System.out.println("In MyThread Current Thread " + Thread.currentThread().getId());
}
}
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("This is Runnable");
System.out.println("In Runnable Current Thread " + Thread.currentThread().getId());
}
}
class MyExecutors {
public static void executeThreads() throws Exception {
ExecutorService executorService = Executors.newFixedThreadPool(2);
FutureTask<String> fts = new FutureTask<String>(new Callable<String>() {
@Override
public String call() throws Exception {
System.out.println("Callable");
return "Current threadid is " + Thread.currentThread().getId();
}
});
executorService.submit(fts);
executorService.shutdown();
ExecutorService es = Executors.newFixedThreadPool(2);
List<Future<String>> futures = new ArrayList<Future<String>>();
for (int i = 0; i < 5; i++) {
futures.add(es.submit(new Task()));
}
for (Future<String> future : futures) {
try {
System.out.println(future.get());
} catch (ExecutionException ee) {
System.err.println(ee.getCause());
}
}
es.shutdown();
}
static class Task implements Callable<String> {
private static AtomicInteger i = new AtomicInteger(1);
public String call() throws Exception {
i.incrementAndGet();
if (i.get() % 2 != 0) {
throw new RuntimeException("That's odd, I failed.");
}
return "I'm done";
}
}
}
线程间的同步方法大体可分为两类:用户模式和内核模式。顾名思义,内核模式就是指利用系统内核对象的单一性来进行同步,使用时需要切换内核态与用户态,而用户模式就是不需要切换到内核态,只在用户态完成操作。
用户模式下的方法有:原子操作(例如一个单一的全局变量),临界区。内核模式下的方法有:事件,信号量,互斥量。
多线程同步和互斥有何异同
线程同步是指线程之间所具有的一种制约关系,一个线程的执行依赖另一个线程的消息,当它没有得到另一个线程的消息时应等待,直到消息到达时才被唤醒。
线程互斥是指对于共享的进程系统资源,在各单个线程访问时的排它性。当有若干个线程都要使用某一共享资源时,任何时刻最多只允许一个线程去使用,其它要使用该资源的线程必须等待,直到占用资源者释放该资源。线程互斥可以看成是一种特殊的线程同步