多线程
进程是一个正在执行中的程序,每个进程执行都有一个执行顺序,或执行路径;
线程是进程中的内容,是进程中独立的控制单元;
线程控制着进程的执行,或者是一个控制单元;
一个进程中至少有一个线程;
1.第一种方式为:
将类声明为Thread的子类,该子类应重写Thread类的run方法
例如:
<pre name="code" class="java">class Demo extends Thread { @Override public void run() { super.run(); } }
2. 第二种方式是实现 Runnable接口,并重写Thread的run方法
class RunnableDemo implements Runnable{ @Override public void run() { } } class TestRunnableClass{ public static void main(String[] args) { RunnableDemo runnableDemo = new RunnableDemo(); Thread t = new Thread(runnableDemo); t . start(); } }
注: 1. 定义类实现Runable接口来创建线程
2. 覆盖 Runable 中run方法,将要执行的代码放入;
3. 通过 Thread 类建立线和对象
4.将 Runnable接口子类对象作为实际参数传递给Thread类的构造函数中
5.调用 Thread类的 start 方法 开户线程
注: 两种创建线程方式的区别:
实现方式的好处,了单继承的局限性
在定义线程时,建议使用实现类
继承Thread: 线程代码存放在Thread类的run方法中
实现Runable,线程将代码存放在接口的子类run方法中
3.注 : 在某一个时刻,只能有一个程序在运行;
在多线程中,有一个特性:随机执行;
d . run();是调用类Demo类中的run方法,而未启动线程
将自定义代码存储在run方法中,让线程运行;
例:
class ThreadDemos1 extends Thread { public void run() { for(int x =0;x<10;x++) { System.out.println(this.getName()+" " + x); } } } //其中 this.getName 是获得线程的名称 class ThreadDemos2 extends Thread { ThreadDemos2(String name) { super(name); } public void run() { for(int x =0;x<10;x++) {System.out.println(this.getName()+" " + x); } } }
public class TestDemo { public static void main(String[] args) { ThreadDemos1 d1 = new ThreadDemos1(); d1.start(); ThreadDemos2 d = new ThreadDemos2("one"); d.start(); } }
阻塞状态
|
线程建立——(start())——运行————sleep()————冻结
|
stop
** 线程都有自己的名称 : Thread-标号 ,, 标号是从0开始的;
** 获得线程名称的方法 : this.getName(); Thread.currentThread().getName()
** 可以在线程初始化始时对线程命名;
class Demoss extends Thread { public void run() { for(int x =0;x<10;x++) { System.out.println(this.getName()+" " + x); } } } public class TestDemo { public static void main(String[] args) { Demoss d1 = new Demoss("one"); d1.start(); } }
class Demos extends Thread { Demos(String name) { super(name); } public void run() { for(int x =0;x<10;x++) { System.out.println(this.getName()+" " + x); } } } public class TestDemo { public static void main(String[] args) { Demos d1 = new Demos("one"); d1.start(); } }
java对于多线程的安全问题,提供了专业的解决方式,就是 使用同步代码块,
结构
synchronized(对象) { 被同步的代码 }
例如一个售票例子
总共1000张票 四个售票机
package test; public class TestDeoo { public static void main(String[] args) { Ticket t = new Ticket(); Thread t1 = new Thread(t); Thread t2 = new Thread(t); Thread t3 = new Thread(t); Thread t4 = new Thread(t); t1.start(); t2.start(); t3.start(); t4.start(); } } class Ticket implements Runnable{ private int tick=1000; Object obj = new Object(); public void run(){ while(true){ synchronized(obj){ if(tick>0){ " try{Thread.sleep(10);}catch(Exception e){ }; } <pre name="code" class="java">
例如有两个线程,当线程0获得CPU的执行权后,会读到synchronized代码块, 判断,然后会获得进入许可,继续执行下面的代码,随后synchronized 关闭入口,读到 stop时,线程结束,此时入口开放,等待下一线程的进入执行。。。。。。。。。。
<1> 必须有两个或者两个以上的线程
<2> 必须是多个线程使用同一个锁
解决了线程的安全问题
多个线程要判断锁,较为消耗资源
例
public class StringDemo { public static void main(String[] args) { Cuss c = new Cuss(); Thread t = new Thread(c); Thread t2 = new Thread(c); t.start(); t2.start(); } } class Bank { private int sum; Object obj = new Object(); public void add(int x) { synchronized (obj) { sum = sum + x; try { Thread.sleep(10); } catch (Exception e) { } System.out.println("sum " + sum); } } } class Cuss implements Runnable { private Bank b = new Bank(); public void run() { for (int x = 0; x < 3; x++) { b.add(100); System.out.println(Thread.currentThread().getName()); } } }
使用同步函数形式来写出上述问题
class Banks { private int sum; Object obj = new Object(); public synchronized void add(int x) { sum = sum + x; try { Thread.sleep(10); } catch (Exception e) { } System.out.println("sum " + sum); } } class Cuss implements Runnable { private Banks b = new Banks(); public void run() { for (int x = 0; x < 3; x++) { b.add(100); System.out.println(Thread.currentThread().getName()); } } } public class stringDemo { public static void main(String[] args) { Cuss c = new Cuss(); Thread t = new Thread(c); Thread t2 = new Thread(c); t.start(); t2.start(); } }
class Single { private static final Single s = new Singles(); private Single() { } public static Single getInstanceP { return s; } }
class Single { private static Single s = null; private Single() { } public static Single getInstance() { if (s == null) { synchronized (Single.class) { if (s == null) { s = new Single(); } } } return s; } }
线程间的的通讯,其实就是多个线程在操作同一个资源;但是操作的动作不同的资源
新建一个资源:
class Res { String name; String sex; }
创建一个输入线程类: 输入与输出线程要操作同一个资源
class Input implements Runnable { Res r; Input(Res r) { this.r=r; } public void run() { boolean b =true; while(true) { if(b) { r.name="lishi"; r.sex="man"; b = false; } else { r.name="李四"; r.sex="男"; b = true; } } } }
class Output implements Runnable { Res r; Output(Res r) { this.r=r; } public void run() { while(true) { System.out.println(r.name); } } }
新建一个测试类
public class TestDemo { public static void main(String[] args) { Res r = new Res(); Input in = new Input(r); Output out = new Output(r); Thread t = new Thread(in ); Thread tl = new Thread(out); t.start(); tl.start(); } }
这个程序的输出结果应该为 lishi man
李四 男
。。。。。
测试一下,会出现乱码现象,如果要修改安全问题,就应该使用同步代码块
class Res { String name; String sex; } class Input implements Runnable { Res r; Input(Res r) { this.r=r; } public void run() { boolean b =true; while(true) { synchronized(r) { if(b) { r.name="lishi"; r.sex="man"; b = false; } else { r.name="李四"; r.sex="男"; b = true; } } } } }
class Output implements Runnable { Res r; Output(Res r) { this.r=r; } public void run() { synchronized(r) { while(true) { System.out.println(r.name+" "+r.sex); } } } }
这样的话就解决了线程间的安全问题了
新建一个资源
class Res { String name; String sex; boolean bo = false; }
class Input implements Runnable { Res r; Input(Res r) { this.r=r; } public void run() { boolean b =true; while(true) { synchronized(r) { if(r.bo) try{r.wait();}catch(Exception e){} if(b) { r.name="lishi"; r.sex="man"; b = false; } else { r.name="李四"; r.sex="男"; b = true; } r.bo =true ; r.notify(); } } } }
class Output implements Runnable { Res r; Output(Res r) { this.r=r; } public void run() { while(true) { synchronized(r) { if(!r.bo) try{r.wait();}catch(Exception e){} System.out.println(r.name+" "+r.sex); r.bo=false; r.notify(); } } } }
public class StringDemo { public static void main(String[] args) { Res r = new Res(); Input in = new Input(r); Output out = new Output(r); Thread t = new Thread(in ); Thread tl = new Thread(out); t.start(); tl.start(); } }
输出结果为
李四 男
lishi man
李四 男
lishi man
李四 男
lishi man
李四 男
lishi man
李四 男
lishi man
李四 男
lishi man
李四 男
lishi man
李四 男
lishi man
李四 男
注 : wait :
notify()
notifyAll()
都使用在同步中,因为要对持有监视器的线程操作,所以要使用在同步中,因为只有 同步才具有锁;
为什么这些操作线程的方法要定义在object 类中呢?
因为这些方法在操作同步线程中,都必须要标识它们所操作线程的锁,只有同一个锁上的被等待线程,可以被同一个锁上的notify唤醒,不可以对不同锁中的线程进行唤醒,也就是说,等待和唤醒必须是同一个锁,而锁可以是任意对象,所以可以被任意对象调用的方法定义在Object类中
优化后的代码
public class TestDemo { public static void main(String[] args) { Resi r = new Resi(); new Thread(new Inputi(r)).start(); new Thread(new Outputi(r)).start(); } } class Resi { String name; String sex; boolean bo = false; public synchronized void set(String name ,String sex) { if(bo) try{this.wait();}catch(Exception e){} this.name = name; this.sex = sex; bo = true ; this.notify(); } public synchronized void out() { if(!bo) try{this.wait();}catch(Exception e){} System.out.println(name +" "+sex); bo = false; this.notify(); } } class Inputi implements Runnable { Resi r; Inputi(Resi r) { this.r = r; } public void run() { boolean b =true; while(true) { if(b) { r.set("lishi","man"); b = false; } else { r.set("李四","男"); b = true; } } } } class Outputi implements Runnable { Resi r; Outputi(Resi r) { this.r = r; } public void run() { while(true) r.out(); }
生产者与消费者 线程间的通信
public class StringDemo { public static void main(String[] args) { Resourced r = new Resourced(); new Thread(new Producerd(r)).start();//1 new Thread(new Producerd(r)).start();//2 new Thread(new Consumerd(r)).start();//3 new Thread(new Consumerd(r)).start();//4 } }
/* * 生产一个,消费一个*/ class Resourced { private String name; private int count = 1; private boolean flag = false; public synchronized void set(String name) { while(flag) try{wait();}catch(Exception e){} this.name = name+" "+count++; System.out.println(Thread.currentThread().getName()+"生产者,,,," + this.name); flag = true; this.notifyAll(); } public void out(){ while(!flag) try{wait();}catch(Exception e){} System.out.println(Thread.currentThread().getName()+"消费者 " + this.name); flag = false; this.notifyAll(); } }
class Producerd implements Runnable { private Resourced res ; Producerd(Resourced res) { this.res = res; } public void run() { while(true) '7B res.set("商品"); } } }
class Consumerd implements Runnable { private Resourced res; Consumerd(Resourced res) { this.res = res; } public void run() { while(true) { res.out(); } } }