java基础第十一天——多线程

  多线程: 当前的程序有多条 执行路径,线程可以理解为就是每一条程序的执行路径
  单进程多线程
 
   什么是进程?
  代表着一个正在运行的应用程序,我们所编写的java程序,就是一个应用程序
 
  什么是线程?
  案例: 迅雷下载
  线程是在进程中存在的,线程可以理解为就是每一条程序的执行路径
 
  
  单进程单线程:  同一时刻, 一个人 过  独木桥,  (进程: 桥,  线程:人)
  单进程多线程:  同一时刻,一个桥,多个人过         (进程: 桥,  线程:人)
  多进程多线程:  同一时刻,多个桥, 有多个人过     (进程: 桥,  线程:人)
  
  
  
  面试题:jvm虚拟机的启动是单线程的还是多线程的?
最少启动了两个线程
第一个线程: 启动主方法的线程, 主线程
第二个线程: 垃圾回收器线程


Thread : 是程序中的执行线程。Java 虚拟机允许应用程序并发地运行多个执行线程。
注意: 创建线程之前,要有进程,而进程我们不能自己创建,它是由操作系统来自动创建的,我们只需要创建线程即可,通过JavaAPI提供的一个类 Thread


创建新执行线程有两种方法:
方式一: 将类声明为 Thread 的子类
1, 创建自定义类,继承与Thread, 这个时候 自定义类就是一个线程类子类
class PrimeThread extends Thread {}
2, 自定义类中 需要重写 Thread类中的 run()方法
class PrimeThread extends Thread {
public void run() {
             . . .
        }
}
3, 创建线程对象
PrimeThread p = new PrimeThread();
4, 启动线程
p.start();
—————————————————————————————
方式2:声明实现 Runnable 接口的类
1,自定义类 实现  Runnable接口
class PrimeRun implements Runnable  {

}
2, 自定义类 实现接口中的抽象方法 run()
class PrimeRun implements Runnable  {
public void run() {
             . . .
        }
}
3, 创建自定义类对象, 它不是线程对象,但是它实现 Runnable接口
PrimeRun p = new PrimeRun();
4, 创建线程对象,并启动
new Thread(p).start();
—————————————————————————————
  Thread类中的基本方法
   为线程起名字
   public final void setName(String name)  改变线程名称,使之与参数 name 相同
  public final String getName()返回该线程的名称
  
   构造方法:
   public Thread(String name) 分配新的 Thread 对象  
—————————————————————————————
 线程使用的注意事项:
  几个小问题:
  1, 线程有默认的名字吗? 有的话 是什么? 有什么样的规则?
  有, 
  Thread-编号,编号从0开始数 
 
2,为什么要重写run()方法??
为了指定每个线程要执行的操作

3, 启动线程使用的是那个方法? run()和start()方法的区别
start();
run();

start(),使该线程开始执行;Java 虚拟机调用该线程的 run 方法
run(), 只是用来指定每个线程要做的事情,就是一个普通方法而已,不能启动线程

4,线程能不能多次启动
指示线程没有处于请求操作所要求的适当状态时抛出的异常
IllegalThreadStateException  
—————————————————————————————
 Thread类的方法
  返回对当前正在执行的线程对象的引用。
  public static Thread currentThread() 
 
  设置和获取线程优先级
public final int getPriority()
public final void setPriority(int newPriority)
IllegalArgumentException 出现 向方法传递了一个不合法或不正确的参数
IllegalArgumentException - 如果优先级不在 MIN_PRIORITY 到 MAX_PRIORITY 范围内。 

public static final int MAX_PRIORITY 10 最大优先级
public static final int MIN_PRIORITY 1 最小优先级
public static final int NORM_PRIORITY 5  默认优先级  
 
  线程休眠
public static void sleep(long millis) 参数为毫秒值
让当前线程休眠指定的时间后,再继续运行

线程加入
public final void join()
等待该线程终止, 其他线程要等该线程执行完毕后 才能执行

线程礼让
public static void yield()
让其他线程获取CPU执行权, 让其他线程运行


后台线程(守护线程)
public final void setDaemon(Daemon(boolean on)
后台线程是用来守护当前线程的, 一旦当前线程结束,守护线程跟着一起结束 

中断线程
public final void stop()  
强迫线程停止执行

public void interrupt()
中断线程。
如果线程在调用 Object 类的 wait()、wait(long) 或 wait(long, int) 方法,
或者该类的 join()、join(long)、join(long, int)、sleep(long) 或 sleep(long, int) 方法过程中受阻,
则其中断状态将被清除,它还将收到一个 InterruptedException。

InterruptedException: 中断异常
在线程启动以后。
如果线程正在等待wait()、休眠sleep()或占用状态join(),且这个时候,调用了interrupt()方法,该线程会被中断,抛出该异常
—————————————————————————————
 发现多线程的代码 出现了 线程安全问题, 为什么会出现线程安全问题?
   1, 处于多线程的环境下 t1,t2,t3
   2, 操作了 共享的数据  (票Ticket)
   3, 多处 对共享数据 票 进行了操作
  
  如何解决线程安全的问题
   (无解)1, 处于多线程的环境下 t1,t2,t3 
  (无解)2, 操作了 共享的数据  (票Ticket)
   (可以解决)3, 多处 对共享数据 票 进行了操作
   把  多处 对共享数据 票 进行了操作 进行封装, 实现让同一时刻只能有一个线程来访问该代码
  
   (锁){
   多处 对共享数据 票
  }
—————————————————————————————
   想通过代码块,把多处 对共享数据 票 进行了操作 进行封装, 可以通过 同步代码块的方式来 完成
  
   同步代码块格式:
   synchronized (锁) {
   把多处 对共享数据 票
   }  
   这里的锁, 就是一个对象,这个对象可以是任意的对象,没有要求
 
  
  同步方法: 在定义方法的时候,写上关键字 synchronized
  private synchronized void method(){....}
  
    静态同步方法: 在定义方法的时候,写上关键字 synchronized
private static synchronized void method(){....}
—————————————————————————————
关于锁对象的问题:
多个线程对象,要求必须使用同一把锁, 也就是同一个锁对象

同步代码块的锁对象:  它是任意的对象

同步方法的锁对象: this

静态同步方法的锁对象:  类名.class ---> 字节码文件对象

Lock: 锁,jdk1.5版本
lock() 上锁
unLock() 解锁
—————————————————————————————
死锁: 是指两个或者两个以上的线程在执行的过程中,因争夺资源产生的一种互相等待现象
synchronized (A){
synchronized (B){
...
}
}

—————————————————————————————
等待唤醒机制: 图解
   public final void wait() throws InterruptedException
   public final void wait(long timeout)  throws InterruptedException
   public final void wait(long timeout,  int nanos)  throws InterruptedException
    上面3个方法的作用是让当前线程对象等待,需要通过 notify()方法或 notifyAll()方法进行唤醒
    当调用该方法后,会释放当前线程对象上的 锁对象, 同时,释放CPU执行权
    Synchronzied (p) {
    ....
    p.wait(); /将某个线程等待
   ...
   
   
   public final void notify()
   唤醒当前锁对象上 处于等待状态的线程
    如果当前锁对象上 有多个线程处于等待状态,会随机唤醒其中的一个线程
  
   public final void notifyAll()
    唤醒当前锁对象上 处于等待状态的线程
    如果当前锁对象上 有多个线程处于等待状态, 会唤醒所有处于等待状态的线程
—————————————————————————————
 Java中使用ThreadGroup来表示线程组,它可以对一批线程进行分类管理,Java允许程序直接对线程组进行控制。
默认情况下,所有的线程都属于主线程组。
public final ThreadGroup getThreadGroup()
我们也可以给线程设置分组

Thread(ThreadGroup group, String name) 
Thread(ThreadGroup group, Runnable target) 
Thread(ThreadGroup group, Runnable target, String name) 
—————————————————————————————
  ThreadPool 线程池:
   好处:
省去了频繁创建线程对象的操作
   创建好的线程对象可以重复使用
  
   JDK5新增了一个Executors工厂类来产生线程池,有如下几个方法
   Executors类中方法:
public static ExecutorService newCachedThreadPool()
public static ExecutorService newFixedThreadPool(int nThreads)
public static ExecutorService newSingleThreadExecutor()

ExecutorService线程池类
Future submit(Runnable task) 
获取线程池中的某一个线程对象,并执行线程中的run()方法
Future submit(Callable task)
获取线程池中的某一个线程对象,并执行线程中的call()方法

//获取线程池中的线程,调用Callable接口子类对象中的call()方法, 完成求和操作
// Future submit(Callable task)
// Future 结果对象
Future result = threadPool.submit(c);
//此 Future 的 get 方法所返回的结果类型
Integer sum = result.get();

使用线程池中线程对象的步骤:
创建线程池对象
创建Runnable实例对象
提交Runnable实例
关闭线程池
—————————————————————————————
匿名内部类方式使用多线程
new Thread(){代码…}.start();
new Thread(new Runnable(){代码…}).start();

new Thread(){
@Override
public void run() {
System.out.println("haha");
}
}.start();

new Thread(new Runnable() {
@Override
public void run() {
System.out.println("heihei");
}
}).start();
—————————————————————————————
Timer: 时钟类
public Timer()
public void schedule(TimerTask task, long delay)
当给定的延迟时间达到后,执行 时钟任务类中的代码

public void schedule(TimerTask task,long delay,long period)
当给定的延迟时间 delay 达到后,执行 时钟任务类中的代码
然后再等指定的时间 period 达到后,重复的执行 时钟任务类中的代码


TimerTask 时钟任务类
public abstract void run()
public boolean cancel()
—————————————————————————————
1, 多线程有几种实现方案,分别是哪几种?


a, 继承Thread类
b, 实现Runnable接口
c, 通过线程池,实现Callable接口




2, 同步有几种方式,分别是什么?
a,同步代码块
b,同步方法
 静态同步方法


3, 启动一个线程是run()还是start()?它们的区别?
启动一个线程是start()

区别:
start: 启动线程,并调用线程中的run()方法
run  : 执行该线程对象要执行的操作




4, sleep()和wait()方法的区别
sleep: 不释放锁对象, 释放CPU使用权
在休眠的时间内,不能唤醒


wait(): 释放锁对象, 释放CPU使用权
在等待的时间内,能唤醒


5, 为什么wait(),notify(),notifyAll()等方法都定义在Object类中
锁对象可以是任意类型的对象


6, 线程的生命周期图
看图
—————————————————————————————
单例设计思想
保证类在内存中只有一个对象

如何实现类在内存中只有一个对象呢?
构造私有
本身提供一个对象
通过公共的方法让外界访问

实现方式:
饿汉式 : 直接创建对象
线程安全的

懒汉式 : 当要用到对象的时候,再创建对象(延迟加载方式)
一个线程对象的时候,线程安全的
多个线程对象的时候,线程不安全, 可以同步机制处理

//保证类在内存中只有一个对象[饿汉式 : 直接创建对象]
public class Son {
//1, 构造方法私有化
private Son(){
}

//本身提供一个对象
private static Son s = new Son();

//通过公共的方法让外界访问
public static Son getInstance(){
return s;
}
}


//保证类在内存中只有一个对象[懒汉式 : 当要用到对象的时候,再创建对象(延迟加载方式)]
public class Girl {
//构造方法私有
private Girl(){
}


//创建本类对象的引用
private static Girl g = null;

//提供通过公共的方法让外界访问
//第一次访问该方法,创建对象
//之后再访问该方法,返回以前创建好的对象
public synchronized static Girl getInstance(){
//第一次访问该方法,创建对象
if (g == null) {
//t1,t2
g = new Girl();
}
//之后再访问该方法,返回以前创建好的对象
return g;
}
}


你可能感兴趣的:(java基础入门,java)