java多线程
线程与进程的区别:
进程为程序的一次执行过程,是计算机资源分配的最小单位
线程是进程中的一个单元执行流,是cpu调度的最小单位
进程间数据很难共享,线程间数据可以共享,进程间相互不影响,线程间会相互影响
java多线程的两种实现方式:
-
继承Thread类并重写run方法:
public class MyThread01 extends Thread { private String name; public ExtendThread(String name){ this.name=name; } public void run(){ for (int i = 0; i <10 ; i++) { System.out.println((name + "运行" + i)); } } }
-
实现Runable接口:
public class ImplementsRunable implements Runnable { private String name; public ImplementsRunable(String name){ this.name=name; } @Override public void run() { for (int i = 0; i <10 ; i++) { System.out.println((name + "运行" + i)); } } }
java中线程的启动:
public class MyThreadTest01 { public static void main(String[] args) { //对于继承自Thread的线程类的启动 MyThread01 thread_a = new MyThread01("线程A"); MyThread01 thread_b = new MyThread01("线程B"); //不能直接调用run方法 // thread_a.run(); // thread_b.run(); thread_a.start(); thread_b.start(); //对于实现Runable接口的线程类的启动 Mythread02 mt1 = new ImplementsRunable("线程A"); Mythread02 mt2 = new ImplementsRunable("线程B"); Thread thread_a = new Thread(mt1); Thread thread_b = new Thread(mt2); thread_a.start(); thread_b.start(); } } }
从上面代码可以看成,不管是那种方式实现多线程,最终都要用到Thread类实例,并调用start()方法启动线程,看似实现Runable接口的线程类用起来还要麻烦一些,但只有实现Runable接口的方式实现的多线程才能实现数据共享
如下代码:
//继承Thread多线程之间不能实现资源共享 public class MyThread extends Thread { private int ticket=5; public void run(){ for (int i = 0; i <=100 ; i++) { if(ticket>0){ System.out.println(("卖票:ticket" + ticket--)); } } } } public class MythreadTest { public static void main(String[] args) { MyThread mt1 = new MyThread(); MyThread mt2 = new MyThread(); MyThread mt3 = new MyThread(); mt1.start(); mt2.start(); mt3.start(); } }
运行结果为:
public class MyRunable implements Runnable {
private int ticket=5;
@Override
public void run() {
for (int i = 0; i <= 100; i++) {
if(ticket>0){
System.out.println(("卖票:ticket" + ticket--));
}
}
}
}
//实现资源共享
public class MyRunableTest {
public static void main(String[] args) {
MyRunable myRunable1 = new MyRunable();
new Thread(myRunable1).start();
new Thread(myRunable1).start();
new Thread(myRunable1).start();
}
}
运行结果为:
线程常用函数:
- join():让该线程强制运行
- yield():暂停该线程
- sleep(int time):让该线程休眠time (ms)
- interrupt():中断线程
- setDeamon():让该线程在后台运行
- setPriority():其参数为Thread.MIN_PRIORITY(最小优先级),Thread.NORM_PRIORITY(中等优先级)和THREAD.MAX_PRIORITY(最大优先级)
同步:
作用:解决多个线程共用一个数据资源而使程序出现问题,如卖票负数问题
实现:
-
同步代码块:synchronized(同步对象)
synchronized(同步对象){ //需要同步的代码 }
-
同步函数:
public synchronized void sale(){ //... }
买票问题的同步实现:
public class ThreadSynchronized implements Runnable { private int ticket=5; @Override public void run() { for (int i = 0; i <=100; i++) { synchronized (this){ if(ticket>0){ try{ Thread.sleep(1000); }catch (Exception e){ e.printStackTrace(); } System.out.println("卖票:ticket"+ticket--); } } } } // public synchronized void sale(){ // if(ticket>0){ // try { // Thread.sleep(1000); // }catch (Exception e){ // e.printStackTrace(); // } // System.out.println("卖票:ticket"+ticket--); // } // } }
死锁:过多的同步产生死锁(如张三李四问题)见下代码
public class ThreadDeadLock implements Runnable { private static Zhangsan zs = new Zhangsan(); private static Lisi ls = new Lisi(); public boolean flag = false; @Override public void run() { if(flag){ synchronized (zs){ zs.say(); try{ Thread.sleep(1000); }catch(Exception e){ e.printStackTrace(); } synchronized (ls){ zs.get(); } } }else{ synchronized (ls){ ls.say(); try{ Thread.sleep(1000); }catch (Exception e){ e.printStackTrace(); } synchronized (zs){ ls.get(); } } } } }
public class Zhangsan { public void say(){ System.out.println("张三对李四说:你给我画我就给你书"); } public void get(){ System.out.println("张三得到画了"); } }
public class Lisi { public void say(){ System.out.println("李四对张三说:你给我书我就给你画"); } public void get(){ System.out.println("李四得到书了"); } }
public class DeadLockTest { public static void main(String[] args) { ThreadDeadLock t1 = new ThreadDeadLock(); ThreadDeadLock t2 = new ThreadDeadLock(); t1.flag = true; t2.flag = false; new Thread(t1).start(); new Thread(t2).start(); } }
输出结果为: