------- android培训、java培训、期待与您交流! ---------- 进程:是一个正在执行中的程序。 每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元。 线程:就是进程中的一个独立的控制单元,线程在控制着进程的执行。 在一个进程中还可以有多个执行单元同时运行,这些执行单元可以看作程序执行的一条条线索,被称为线程。操作系统中的每一个进程中都至少存在一个线程。 Java VM 启动的时候会有一个进程 java.exe,该进程中至少一个线程负责Java程序的执行。而且这个线程运行的代码存在于main方法中。该线程称之为主线程。 扩展:其实更细节说明jvm启动不止一个线程,还有负责垃圾回收机制的线程。 1.如何在自定义的代码中,自定义一个线程呢? 通过对api的查找,java已经提供了对线程这类事物的描述。就Thread类。 创建线程的第一种方式:继承Thread类。(重写run()方法) 步骤: 1,定义类继承Thread。 2,复写Thread类中的run方法。 目的:将自定义代码存储在run方法,让线程运行。 3,调用线程的start方法,该方法两个作用: 启动线程;调用run方法。 发现运行结果每一次都不一样。因为多个线程都获取cpu的执行权。cpu执行到谁,谁就运行。明确一点,在某一个时刻,只能有一个线程在运行。(多核除外)cpu在做着快速切换,已达到看上去是同时运行的效果。我们可以形象的把多线程的运行认为在互相抢夺cpu的执行权。这就是多线程的一个特性:随机性,谁抢到谁执行,至于执行多长时间,cpu说的算。 为什么要覆盖run方法呢? Thread类用于描述线程。该类就定义了一个功能,用于存储线程要运行的道代码,该存储功能就是run方法。也就是说Thread类中的run方法,用于存储线程要运行的代码。 */ class Demo extends Thread { public voidrun() { for(intx=0;x<60;x++) System.out.println("demorun——"+x); } } class ThreadDemo { public staticvoid main(String[] args) { Demo d =new Demo();//创建好一个线程 d.start();//开启线程并执行该线程的run方法。 //d.run();一般调用执行run方法,并没有开启线程,是主线程在执行。 for(intx=0;x<60;x++) System.out.println("HelloWorld——"+x); } } 需求:简单的买票程序。多个窗口同时买票 创建线程的第二种方式:实现Runnable接口。 步骤: 1,定义类实现Runnable接口。 2,覆盖Runnable接口中的run方法。 将线程要运行的代码存放在该run方法中。 3,通过Thread类建立线程对象。 4,将Runnable接口的子类对象作为实现参数传递给Thread类得构造函数。为什么要将Runnable接口的子类对象传递给Thread的构造函数。因为,自定义的run方法所属的对象是Runnable就扣的子类对象。所以要让线程去指定对象的run方法,就必须明确该run方法所属的对象。 5,调用Thread类得start方法开启线程并调用Runnable接口子类的run方法。 实现方式和继承方式有什么区别呢? 实现方式的好处:避免了单继承的局限性。 在定义线程时,建议使用实现方式。 两种方式区别: 继承Thread:线程代码存放Thread子类run方法中。 实现Runnable,线程代码存放在接口的子类的run方法中。 */ class Ticket implements Runnable { private inttick = 100; public voidrun() { while(true) { if(tick>0) { //获取的是线程对象 getName()获取线程名称 System.out.println(Thread.currentThread().getName()+"...sale:"+tick--); } } } } //设置线程名称setName(),或者使用构造函数 class TicketDemo { public staticvoid 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,-1,-2等错票。 多线程的运行出现了安全问题。 问题原因: 当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完。 另一个线程参与进来执行,导致共享数据的错误。(tick就是本程序的共享数据)。 解决办法: 对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其他线程不可以参与执行。 java对于多线程的安全问题提供了专业的解决方式。 就是同步代码块: synchronized(对象) { 需要被同步的代码。(就是多个线程共享数据的部分) } 对象如同锁,持有锁的线程可以在同步中执行, 没有持有锁的线程即使获取cpu的执行权,也进不去,因为没有获取锁。 火车上的卫生间————经典。 同步的前提: 1,必须要有两个或者以上的线程。 2,必须是多个线程使用同一个锁。 必须保证同步中只能有一个线程在运行。 好处:解决了多线程的安全问题。 弊端:多个线程需要判断锁,较为消耗资源。 */ class Ticket implements Runnable { private inttick = 1000; Object obj =new Object(); public voidrun() { while(true) { synchronized(obj) { if(tick>0) { try{Thread.sleep(10);}catch(Exceptione){} System.out.println(Thread.currentThread().getName()+"...sale:"+tick--); } } } } } class TicketDemo2 { public staticvoid main(String[] args) { Ticket t= new Ticket();//此对象还不是线程,真正的线程是Thread和其子类对象 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(); } } 同步函数用的是哪一个锁呢? 函数需要被对象调用。那么函数都有一个所属对象引用,就是this。所以同步函数使用的锁是this。通过改程序进行验证。使用两个线程来买票一个线程在同步代码块中,一个线程在同步函数中,都在执行买票动作。 */ class Ticket implementsRunnable { private int tick = 100; Object obj = new Object(); boolean flag = true; public void run() { if(flag) { while(true) { synchronized(this) { if(tick>0) { try{Thread.sleep(10);}catch(Exceptione){} System.out.println(Thread.currentThread().getName()+"...code:"+tick--); } } } } else while(true) show(); } publicsynchronized void show() { if(tick>0) { try{Thread.sleep(10);}catch(Exceptione){} System.out.println(Thread.currentThread().getName()+"...show:"+tick--); } } } class ThisLockDemo { public staticvoid main(String[] args) { Ticket t= new Ticket(); Thread t1= new Thread(t); Thread t2= new Thread(t); t1.start(); try{Thread.sleep(10);}catch(Exceptione){} t.flag =false; t2.start(); //Threadt3 = new Thread(t); //Threadt4 = new Thread(t); //t3.start(); //t4.start(); } } 如果同步函数被静态修饰后,使用的锁是什么呢? 通过验证,发现不是this,因为静态方法中也不可以定义this。静态进内存时,内存中没有本类对象,但是一定有该类对应的字节码文件对象。类名.class该对象的类型是class 静态的同步方法,使用的锁是该方法所在类得字节码文件对象。类名.class 死锁,开发时要避免死锁的情况 classTest implements Runnable { private boolean flag; Test(boolean flag) { this.flag = flag; } public void run() { if(flag) { while(true) { synchronized(MyLock.locka) { System.out.println("iflocka"); synchronized(MyLock.lockb) { System.out.println("iflockb"); } } } } else { while(true) { synchronized(MyLock.lockb) { System.out.println("elselockb"); synchronized(MyLock.locka) { System.out.println("elselocka"); } } } } } } classMyLock { static Object locka = new Object(); static Object lockb = new Object(); } class DeadLockTest { public static void main(String[] args) { Thread t1 = new Thread(new Test(true)); Thread t2 = new Thread(new Test(false)); t1.start(); t2.start(); } } 单例设计模式: 饿汉式: class Single { privatestatic final Single s = new Single(); privateSingle(){} public staticSingle getInstance() { return s; } } */ //懒汉式: 实例的延迟加载,延迟加载有问题,加同步解决问题,用同步函数和同步代码块都可以,但是有些低效,用双重判断的形式可以提高效率 class Single { private static Single s = null; privateSingle(){} public staticSingle getInstance() { if(s==null) { synchronized(Single.class) { if(s==null) s= new Single(); } } return s; } } class SingleDemo { public staticvoid main(String[] args) { System.out.println("HelloWorld!"); } }