今天记录Java中最重要的一个知识点------多线程!!!
进程:就是应用程序在内存中分配的空间。(正在运行中的程序) 线程:是进程中负责程序执行的执行单元。也称为执行路径。 一个进程中至少有一个线程在负责该进程的运行。 如果一个进程中出现了多个线程,就成该程序为多线程程序。 举例:运动场--鸟巢。水立方。 多线程技术:解决多部分代码同时执行的需求。合理的使用cpu资源。
/* 多线程的运行根据cpu的切换完成的。怎么切换cpu说的算, 所以多线程运行有一个随机性(cpu的快速切换造成的)。 jvm中的多线程。 至少有两个线程:一个是负责自定义代码运行的。这个从main方法开始执行的线程称之为主线程。 一个是负责垃圾回收的。 通过实验,会发现每次结果不一定相同,因为随机性造成的。 而且每一个线程都有运行的代码内容。这个称之为线程的任务。 之所以创建一个线程就是为了去运行制定的任务代码。 而线程的任务都封装在特定的区域中。 比如: 主线程运行的任务都定义在main方法中。 垃圾回收线程在收垃圾都会运行finalize方法。 */ class Demo { //定义垃圾回收方法。 public void finalize() { System.out.println("demo ok"); } } class FinalizeDemo { public static void main(String[] args) { System.gc();//启动垃圾回收器。 new Demo(); new Demo(); new Demo(); System.out.println("Hello World!"); } } /* final , finally , finalize有什么区别? */
/* 如何建立一个执行路径呢? 通过查阅api文档 java.lang.Thread类。 该类的描述中有创建线程的两种方式: 1,继承Thread类。 1,继承Thread类。 2,覆盖run方法。 3,创建子类对象就是创建线程对象。 4,调用Thread类中的start方法就可以执行线程。并会调用run方法。 start()开启线程后,都会执行run方法。说明run方法中存储的是线程要运行的代码。 所以,记住,自定义线程的任务代码都存储在run方法中。 */ class Demo extends Thread { private String name; Demo(String name) { //super(); this.name = name; } //覆盖run方法。 public void run() { for(int x=1; x<=40; x++) { System.out.println(this.getName()+"....."+name+"...."+x); System.out.println(Thread.currentThread().getName()+"....."+name+"...."+x); } } } /* 调用start和调用run方法的区别? 调用start会开启线程,让开启的线程去执行run方法中的线程任务。 直接调用run方法,线程并未开启,去执行run方法的只有主线程。 */ class ThreadDemo { public static void main(String[] args) { Demo d1 = new Demo("张三");//Thread-0 Demo d2 = new Demo("麻子"); d1.start();//start():两件事:1,开启线程,2,调用run方法。 d2.start(); for(int x=1; x<40; x++) { System.out.println(Thread.currentThread().getName()+"--------"+x); } } }
经典实例:卖票
class SaleTicket extends Thread { private int tickets = 100;// //卖票的代码需要被多个线程执行,所以要将这些代码定义在线程任务中。run方法。 public void run() { while(true) { if(tickets>0) { System.out.println(Thread.currentThread().getName()+"...."+tickets--); } } } } class TicketDemo { public static void main(String[] args) { //创建四个线程。会创建400张票。不合适,不建议票变成静态的,所以如何共享这100张票。需要将资源和线程分离。 //到api中查阅了第二创建线程的方式。 SaleTicket t1 = new SaleTicket(); SaleTicket t2 = new SaleTicket(); SaleTicket t3 = new SaleTicket(); SaleTicket t4 = new SaleTicket(); t1.start(); t1.start(); t1.start(); t1.start(); } }
/* 创建线程的第二种方式。实现Runnable接口。 1,定义一个类实现Runnable。 2,覆盖Runnable接口中的run方法,将线程要运行的任务代码存储到该方法中。 3,通过Thread类创建线程对象,并将实现了Runnable接口的对象作为Thread类的构造函数的参数进行传递。 4,调用Thread类的start方法,开启线程。 实现Runnble接口的好处: 1,避免了继承Thread类的单继承的局限性。 2,Runnable接口出现更符合面向对象,将线程单独进行对象的封装。 3,Runnable接口出现,降低了线程对象和线程任务的耦合性。 所以,以后创建线程都使用第二种方式。 */ class SaleTicket implements Runnable { private int tickets = 100; public void run() { while(true) { if(tickets>0) { System.out.println(Thread.currentThread().getName()+"...."+tickets--); } } } } class TicketDemo2 { public static void main(String[] args) { //线程任务对象。 SaleTicket t = new SaleTicket(); //创建四个线程。通过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(); } }
/* 两个储户,到同一个银行存钱,每个人存了3次,一次100元。 1,描述银行。 2,描述储户任务。 分析多线程是否存在安全隐患。 1,线程任务中是否有共享的数据。 2,是否多条操作共享数据的代码。 */ class Bank { private int sum; private Object obj = new Object(); public void add(int n) { synchronized(obj) { sum = sum + n; try{Thread.sleep(10);}catch(Exception e){} System.out.println("sum="+sum); } } } class Customer implements Runnable { private Bank b = new Bank(); public void run() { for(int x=0; x<3; x++) { b.add(100); } } } class ThreadTest { public static void main(String[] args) { //1,创建任务对象。 Customer c = new Customer(); Thread t1 = new Thread(c); Thread t2 = new Thread(c); t1.start(); t2.start(); } }
/* 多线程的安全问题。 产生的原因: 1,线程任务中有处理到共享的数据。 2,线程任务中有多条对共享数据的操作。 一个线程在操作共享数据的过程中,其他线程参与了运算,造成了数据的错误。 解决的思想: 只要保证多条操作共享数据的代码在某一时间段,被一条线程所执行, 在执行期间不允许其他线程参与运算。 咋保证呢? 用到了同步代码块。 synchronized(对象) { 需要被同步的代码。 } 同步在目前情况下保证了一次只能有一个线程在执行。其他线程进不来。 这就是同步的锁机制。 好处:解决了多线程的安全问题。 弊端:减低效率。 有可能出现这样一种情况: 多线程安全问题出现后,加入了同步机制,没有想到,安全问题依旧!咋办。 这时肯定是同步出了问题。 只要遵守了同步的前提,就可以解决。 同步的前提: 多个线程在同步中必须使用同一个锁。这才是对多个线程同步。 */ class SaleTicket implements Runnable { private int tickets = 100; Object obj = new Object(); public void run() { while(true) { synchronized(obj) { if(tickets>0) { try{Thread.sleep(10);}catch(InterruptedException e){}//让线程到这里稍微停一下。 System.out.println(Thread.currentThread().getName()+"...."+tickets--); } } } } } class TicketDemo3 { public static void main(String[] args) { SaleTicket t = new SaleTicket(); //创建四个线程。通过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(); } }