通常,用并发结局的问题大体上可以分为“速度”和“设计可管理性”两种。
频繁的线程间切换
,有效的避免“阻塞
”问题;仿真
相关的问题。java中通常有两种方式创建线程:
扩展java.lang.Thread类
public class taskT extends Thread{
public void run() {
System.out.println("正在执行Runnable!");
}
public static void main(String[] args) {
Thread t =new taskT();
t.start();
}
}
实现java.lang.Runnable接口
public class taskR implements Runnable{
@Override
public void run() {
System.out.println("正在执行Runnable!");
}
}
public static void main(String[] args) {
taskR r = new taskR();
Thread thread = new Thread(r);
thread.start();
}
一旦创建一个新线程并开始执行,即调用start方法时,虚拟机中就又多一个进程,这个进程和原先的进程时并行的。
public class TaskR implements Runnable{
@Override
public void run() {
System.out.println("正在执行线程B!");
System.out.println("已经执行完线程B!");
}
}
public class test {
public static void main(String[] args) {
System.out.println("正在执行main函数111!");
TaskR b = new TaskR();
Thread threadB = new Thread(b);
System.out.println("准备添加线程B!");
threadB.start();
System.out.println("继续执行main函数222!");
// for (int i = 0; i < 999999; i++);//延时代码
System.out.println("正在执行main函数333!");
}
}
如上程序执行结果输出如下:
正在执行main函数111!
准备添加线程B!
继续执行main函数222!
正在执行main函数333!
正在执行线程B!
已经执行完线程B!
将main函数的注释代码去除注释,增加代码延时,输出如下:
正在执行main函数111!
准备添加线程B!
继续执行main函数222!
正在执行线程B!
已经执行完线程B!
正在执行main函数333!
由上两组对比不难发现,当线程threadB一旦开始执行(执行threadbB.start()),main函数这条线程和线程threadB是并发的。
另外需要注意的是,多线程表面上给人的感觉是多个任务同时进行,实际上并非如此,虚拟机通过频繁的切换进程来给人同时执行的错觉。
线程的状态是线程控制的基础。线程状态总的可以分为五大类:生、等待、阻塞、睡眠、死。
当多个线程同时访问互斥(可交换)数据时,应该同步以保护数据,确保两个线程不会同时更改它。通常用synchronized字段实现,而且只能同步方法或同步代码快。
如果两个线程要执行一个类中的synchronized方法,并且两个线程使用相同的实例来调用方法,那么一次只能有一个线程能够执行方法,另一个需要等待,直到锁被释放。
合并:join():join()方法是是在某个线程a中,加入一个线程b,线程b没执行完前,a不得执行。
public class TaskR implements Runnable{
@Override
public void run() {
System.out.println("正在执行线程B!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("已经执行完线程B!");
}
}
public class test {
public static void main(String[] args) throws InterruptedException {
System.out.println("正在执行main函数!");
TaskR b = new TaskR();
Thread threadB = new Thread(b);
System.out.println("准备添加线程B!");
threadB.start();
System.out.println("执行完main");
}
}
public class test2 {
public static void main(String[] args) throws InterruptedException {
System.out.println("正在执行main函数!");
TaskR b = new TaskR();
Thread threadB = new Thread(b);
System.out.println("准备添加线程B!");
threadB.start();
System.out.println("threadB.join()");
threadB.join();
System.out.println("执行完main");
}
}
分别执行test1和test2中的main执行结果如下:
正在执行main函数!
准备添加线程B!
threadB.join()
执行完main
正在执行线程B!
已经执行完线程B!
test2中添加join()方法:
正在执行main函数!
准备添加线程B!
threadB.join()
正在执行线程B!
已经执行完线程B!
执行完main
在threadB中调用sleep是为了让main函数这条线程获得执行机会。有结果,可知当threadB调用join方法后,即使sleep了main函数都不能跑完,说明join方法的作用,即必须threadB执行完才能继续执行main函数。
java.util.concurrent.Executors。 例:
ExecutorService pool = Executors.newFixedThreadPool(2);
Thread t1 = new MyThread();
Thread t2 = new MyThread();
Thread t3 = new MyThread();
Thread t4 = new MyThread();
pool.execute(t1);
pool.execute(t2);
pool.execute(t3);
pool.execute(t4);
pool.shutdown();