进程 :正在进行中的程序(直译)。
线程 :就是进程中一个负责程序执行的控制单元(执行路径) 一个进程中可以有多个执行路径,称之为多线程。
一个进程中至少要有一个线程。
开启多个线程是为了同时运行多部分代码。
每一个线程都有自己运行的内容。这个内容可以称为线程要执行的任务。
多线程的好处:解决了多部分同时运行的问题。
多线程的弊端:线程太多回到效率的降低。
其实应用程序的执行都是cpu在做着快速的切换完成的。这个切换是随机的。
jvm启动时就启动了多个线程,至少有两个线程可以分析的出来。
1。执行main函数的线程 该线程的任务代码都定义在main函数中 2。负责垃圾回收的线程.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
class extends Object { public void finalize () { System.out.println("demo ok" ); } } class ThreadDemo { public static void main (String[] args) { new Demo(); new Demo(); new Demo(); System.gc(); System.out.println("Hello World!" ); } }
多线程的创建方式—继承Thread类
步骤: 1。定义一个类继承Thread类 2。覆盖Thread类中的run方法 3。直接创建Thread的子类对象创建线程 4。调用start方法开启线程并调用线程的任务run方法执行。
可以通过Thread的getName获取线程的名称Thread-编号(从0开始)
主线程的名字就是main.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
class extends Thread { private String name; Demo(String name) { super (name); this .name = name; } public void run () { show(); } public void show () { System.out.println(name+"........x=" +x+".......name=" +Thread.currentThread().getName()); } } class ThreadDemo2 { public static void main (String[] args) { Demo d1 = new Demo("旺财" ); Demo d2 = new Demo("xiaoqiang" ); d1.start(); d2.start(); System.out.println("over....." +Thread.currentThread().getName()); } }
创建多线程的第二种方式—实现Runnable接口
1。定义类实现Runnable接口 2。覆盖接口中的run方法,将线程的任务代码封装到run方法中。 3。通过Thread类创建线程对象,并将Runnable接口的子类对象作为Thread类的构造函数的参数进行传递。 为什么? 因为线程的任务都封装在Runnable接口子类对象的run方法中 所以要在线程对象创建时就必须明确要运行的任务。 4。调用线程对象的start方法开启线程.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
class implements Runnable { public void run () { show(); } public void show () { for (int x=0 ; x<20 ; x++ ) { System.out.println(Thread.currentThread().getName()+"....." +x); } } } class TreadDemo { public static void main (String[] args) { Demo d = new Demo(); Thread t1 = new Thread(d); Thread t2 = new Thread(d); t1.start(); t2.start(); } }
实现Runnable接口的好处 : 1。将线程的任务从线程的子类中分离出来,进行了单独的封装。 按照面向对象的思想将任务的封装成对象。 2。避免了java单继承的局限性。
所以,创建线程的第二种方式较为常用.
例子:卖票。 四个人一起卖100张票
第一种方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
class Ticket extends Thread { private static int num = 100 ; public void run () { sale(); } public void sale () { while (true ) { if (num>0 ) { System.out.println(num--); } } } } class TicketDemo { public static void main (String[] args) { Ticket t1 = new Ticket(); Ticket t2 = new Ticket(); Ticket t3 = new Ticket(); Ticket t4 = new Ticket(); t1.start(); t2.start(); t3.start(); t4.start(); } }
第二种方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
class Ticket implements Runnable { private int num = 100 ; public void run () { sale(); } public void sale () { while (true ) { if (num>0 ) { try {Thread.sleep(10 );}catch (InterruptedException e){} System.out.println(Thread.currentThread().getName()+"....." +num--); } } } } class TicketDemo { 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(); } }
线程安全问题产生的原因 :
1。多个线程在操作共享数据。 2。操作共享数据的线程代码有多条。
当一个线程在执行操作共享数据的多条代码过程中,其他线程参与了运算, 就会导致线程安全问题的产生。
解决思路: 就是将多条操作共享数据的线程代码封装起来,当有线程在执行这些代码的时候, 其他线程是不可以参与运算的。 必须要当前线程把这些代码都执行完毕后,其他线程才可以参与运算。
在java中用,同步代码块就可以解决这个问题.
同步代码块
格式:
1 2 3 4
synchronized (对象) { 需要被同步的代码 }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
class Ticket implements Runnable { private int num = 100 ; Object obj = new Object(); public void run () { sale(); } public void sale () { while (true ) { synchronized (obj) { if (num>0 ) { try {Thread.sleep(10 );}catch (InterruptedException e){} System.out.println(Thread.currentThread().getName()+"....." +num--); } } } } } class TicketDemo { 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(); } }
同步的好处:解决了线程的安全问题。 同步的弊端:相对降低了效率,因为同步外的线程的都会判断同步锁。 同步的前提:必须有多个线程并使用同一锁.
实例:储户,两个,每个都到银行存钱,每次存100,共存三次。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
class Bank { private int sum; public synchronized void add (int num) { sum = sum + num; System.out.println("sum=" +sum); } } class Cus implements Runnable { private Bank b = new Bank(); public void run () { for (int x=0 ; x<3 ; x++ ) { b.add(100 ); } } } class BankDemo { public static void main (String[] args) { Cus c = new Cus(); Thread t1 = new Thread(c); Thread t2 = new Thread(c); t1.start(); t2.start(); } }
验证同步函数的锁
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
class Ticket implements Runnable { private int num = 100 ; Object obj = new Object(); boolean flag = true ; public void run () { if (flag) { while (true ) { synchronized (this ) { if (num>0 ) { try {Thread.sleep(10 );}catch (InterruptedException e){} System.out.println(Thread.currentThread().getName()+"...obj..." +num--); } } } } else while (true ) show(); } public synchronized void show () { if (num>0 ) { try {Thread.sleep(10 );}catch (InterruptedException e){} System.out.println(Thread.currentThread().getName()+"...function..." +num--); } } } class SynFunctionLockDemo { public static void main (String[] args) { Ticket t = new Ticket(); Thread t1 = new Thread(t); Thread t2 = new Thread(t); t1.start(); try {Thread.sleep(10 );}catch (InterruptedException e){} t.flag = false ; t2.start(); } }
同步函数使用的锁是this。
同步函数和同步代码块的区别: 同步函数的锁是固定的this。 同步代码块的锁是任意对象。
建议使用同步代码块.
验证静态同步函数的锁
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
class Ticket implements Runnable { private static int num = 100 ; Object obj = new Object(); boolean flag = true ; public void run () { if (flag) { while (true ) { synchronized (this ) { if (num>0 ) { try {Thread.sleep(10 );}catch (InterruptedException e){} System.out.println(Thread.currentThread().getName()+"...obj..." +num--); } } } } else while (true ) this .show(); } public static synchronized void show (Ticket.class) { if (num>0 ) { try {Thread.sleep(10 );}catch (InterruptedException e){} System.out.println(Thread.currentThread().getName()+"...function..." +num--); } } } class SynFunctionLockDemo { public static void main (String[] args) { Ticket t = new Ticket(); Thread t1 = new Thread(t); Thread t2 = new Thread(t); t1.start(); try {Thread.sleep(10 );}catch (InterruptedException e){} t.flag = false ; t2.start(); } }
静态的同步函数使用的锁是该函数所属字节码文件对象可以用getClass方法获取,也可以用当前 类名.class 表示.
多线程下的单例 饿汉式
1 2 3 4 5 6 7 8 9
class Single { private static final Single s = new Single(); private Single () {} public static Single getInstance () { return s; } }
懒汉式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
class Single { private static Single s = null ; private Single () {} public static synchronized Single getInstance () { if (s==null ) s = new Single(); return s; } } class Single { private static final Single s = null ; private Single () {} public static Single getInstance () { if (s==null ) { synchronized (Single.class) { if (s==null ) { s = new Single(); } } } return s; } }
死锁示例 死锁:常见情景之一:同步的嵌套。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
class Ticket implements Runnable { private static int num = 100 ; Object obj = new Object(); boolean flag = true ; public void run () { if (flag) { while (true ) { synchronized (obj) { show(); } } } else while (true ) this .show(); } public static synchronized void show () { synchronized (obj) { if (num>0 ) { try {Thread.sleep(10 );}catch (InterruptedException e){} System.out.println(Thread.currentThread().getName()+"...sale..." +num--); } } } } class SynFunctionLockDemo { public static void main (String[] args) { Ticket t = new Ticket(); Thread t1 = new Thread(t); Thread t2 = new Thread(t); t1.start(); try {Thread.sleep(10 );}catch (InterruptedException e){} t.flag = false ; t2.start(); } }
一种死锁示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
class Test implements Runnable { private boolean flag; Test(boolean flag) { this .flag = flag; } public void run () { if (flag) { while (true ) { synchronized (MyLock.locka) { System.out.println(Thread.currentThread().getName()+"...if locka......" ); synchronized (MyLock.lockb) { System.out.println(Thread.currentThread().getName()+"...if lockb....." ); } } } } else { while (true ) { synchronized (MyLock.lockb) { System.out.println(Thread.currentThread().getName()+"...else lockb......" ); synchronized (MyLock.locka) { System.out.println(Thread.currentThread().getName()+"...else locka......" ); } } } } } } class MyLock { public static final Object locka = new Object(); public static final Object lockb = new Object(); } class DeadLockTest { public static void main (String[] args) { Test a = new Test(true ); Test b = new Test(false ); Thread t1 = new Thread(a); Thread t2 = new Thread(b); t1.start(); t2.start(); } }
近期评论