我的java基础学习易错点和易忘点总结(三)多线程

十五. 多线程

多线程的存在,不是提高程序的执行速度。其实是为了提高应用程序的使用率。
程序的执行其实都是在抢CPU的资源,CPU的执行权。
多个进程是在抢这个资源,而其中的某一个进程如果执行路径比较多,就会有更高的几率抢到CPU的执行权。
我们是不敢保证哪一个线程能够在哪个时刻抢到,所以线程的执行有随机性。

  1. 进程和线程
  • 进程:
    正在运行的程序,是系统进行资源分配和调用的独立单位。
    每一个进程都有它自己的内存空间和系统资源。
  • 线程:
    是进程中的单个顺序控制流,是一条执行路径
    一个进程如果只有一条执行路径,则称为单线程程序。
    一个进程如果有多条执行路径,则称为多线程程序。
  • 并行和并发:前者是逻辑上同时发生,指在某一个时间内同时运行多个程序。后者是物理上同时发生,指在某一个时间点同时运行多个程序。
  • Java程序的运行原理:由java命令启动JVM,JVM启动就相当于启动了一个进程。接着有该进程创建了一个主线程去调用main方法。
  1. 创建线程方式:
  • 方式1:继承Thread类。
    步骤
    A:自定义类MyThread继承Thread类。
    B:MyThread类里面重写run()?
    为什么是run()方法呢?
    C:创建MyThread对象
    D:启动线程
  • 方式2:实现Runnable接口
    步骤:
    A:自定义类MyRunnable实现Runnable接口
    B:重写run()方法
    C:创建MyRunnable类的对象
    D:创建Thread类的对象,并把C步骤的对象作为构造参数传递
  • 方式3:线程池方式(了解)
    步骤:
    1. 创建一个线程池对象,控制要创建几个线程对象。
      public static ExecutorService newFixedThreadPool(int nThreads)
    2. 这种线程池的线程可以执行:
      可以执行Runnable对象或者Callable对象代表的线程
      做一个类实现Runnable接口。
    3. 调用如下方法即可
      Future submit(Runnable task)
      Future submit(Callable task)
    4. 我就要结束,可以吗?
      可以。shutdown()
  1. 线程安全问题
    • 哪些原因会导致出问题:(而且这些原因也是以后我们判断一个程序是否会有线程安全问题的标准)
      A:是否是多线程环境
      B:是否有共享数据
      C:是否有多条语句操作共享数据
  2. 同步代码块
    synchronized(对象){
    需要同步的代码
    }
  • 对象:指的是多个线程使用的是同一把锁对象
  • 好处:解决了多线程的安全问题
  • 弊端:当线程相当多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率。容易产生死锁。
  1. Lock:ReentrantLock是Lock的实现类.
void lock(): 获取锁。
void unlock():释放锁。  
  1. 线程相关的方法
    如何获取线程对象的名称呢?
public final String getName():获取线程的名称。

如何设置线程对象的名称呢?

public final void setName(String name):设置线程的名称

针对不是Thread类的子类中如何获取线程对象名称呢?

public static Thread currentThread():返回当前正在执行的线程对象
Thread.currentThread().getName()

如何获取线程对象的优先级?

public final int getPriority():返回线程对象的优先级

如何设置线程对象的优先级呢?

public final void setPriority(int newPriority):更改线程的优先级。

线程默认优先级是5。线程优先级的范围是:1-10。
线程优先级高仅仅表示线程获取的 CPU时间片的几率高,但是要在次数比较多,或者多次运行的时候才能看到比较好的效果。

* 线程休眠 public static void sleep(long millis)
----------------------------------------
* public final void join():等待该线程终止。(那个线程调用,那么这个线程就先执行完。)
----------------------------------------
* public static void yield():暂停当前正在执行的线程对象,并执行其他线程。 
* 让多个线程的执行更和谐,但是不能靠它保证一人一次。
----------------------------------------
* public final void setDaemon(boolean on):将该线程标记为守护线程或用户线程。那么当非守护线程执行结束后,该线程会自动停止。(被保护线程(非守护线程)执行结束后,守护线程就会自动停止。)
* 当正在运行的线程都是守护线程时,Java 虚拟机退出。 该方法必须在启动线程前调用。 
----------------------------------------
* public final void stop():让线程停止,过时了,但是还可以使用。太过暴力不建议使用。
* public void interrupt():中断线程。 把线程的状态终止,并抛出一个InterruptedException。
========================================
* Object类中等待唤醒方法:(可以保证两个线程交替执行)
	wait():等待,并且立即释放锁(放弃执行权)		
	notify():唤醒单个线程,唤醒不表示立马可以执行,必须还得再次抢CPU执行权
	notifyAll():唤醒所有线程,唤醒不表示立马可以执行,必须还得再次抢CPU执行权
为什么这些方法不定义在Thread类中呢?
	这些方法的调用必须通过锁对象调用,而我们刚才使用的锁对象是任意锁对象。所以,这些方法必须定义在Object类中。
  1. 线程组:把多个线程组合到一起。它可以对一批线程进行分类管理,Java允许程序直接对线程组进行控制。
ThreadGroup tg = new ThreadGroup("这是一个新的组");//新建一个新的线程组
MyRunnable my = new MyRunnable();//实现了Runnadle接口
Thread t1 = new Thread(tg, my, "林青霞");
tg.setDaeon(true);//通过组名称设置后台线程,表示改组的线程都是后台线程
> 线程类里面的方法:public final ThreadGroup getThreadGroup()
> 线程组里面的方法:public final String getName()(默认情况下是属于main线程的)
	即等于:Thread.currentThread().getThreadGoup().getName()
----------------------------------------

8.线程池:

  • 线程池的好处:线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用。
  • 如何实现线程的代码呢?
  1. 创建一个线程池对象,控制要创建几个线程对象。
public static ExecutorService newFixedThreadPool(int nThreads)
  1. 这种线程池的线程可以执行:
    可以执行Runnable对象或者Callable对象代表的线程
    做一个类实现Runnable接口。
  2. 调用如下方法即可
    Future<?> submit(Runnable task)
    <T> Future<T> submit(Callable<T> task)
    
    注意:submit方法执行完之后,程序不会终止,因为2线程没有被销毁,只是没pool回收。
  3. 我就要结束,可以吗?
    可以。pool.shutdown()方法
  • 例如:
public class ExecutorsDemo {
	public static void main(String[] args) {
		// 创建一个线程池对象,控制要创建几个线程对象。
		// public static ExecutorService newFixedThreadPool(int nThreads)
		ExecutorService pool = Executors.newFixedThreadPool(2);

		// 可以执行Runnable对象或者Callable对象代表的线程
		pool.submit(new MyRunnable());//MyRunnable实现了Runnable接口
		pool.submit(new MyRunnable());

		//结束线程池
		pool.shutdown();
	}
}
  1. 匿名内部类实现多线程:本质:是该类或者接口的子类对象。
  • 继承Thread类来实现多线程
    格式:new Thread(){重写run方法}.start();这里的Thread表示Thread子类对象
  • 实现Runnable接口来实现多线程
    格式:new Thread(new Runnable(){重写run方法}){}.start();这里的Thread表示Thread类本身
  • 继承Thread类、且实现Runnable接口来实现多线程:但是这种线程不会报错而且只会执行子类对象的run(了解认识即可)
    格式:new Thread(new Runnable(){重写run方法}){重写run方法}.start();
start()方法是用来启动线程,并由jvm自动调用run()方法
run()方法封装了被线程执行的代码,直接调用就只是普通方法而已
sleep()必须制定时间,不释放锁
wait()可以不指定时间,也可以指定时间,他是释放锁的
  1. 使用线程安全类(了解)
public static <T> List<T> synchronizedList(List<T> list)

你可能感兴趣的:(java)