CoreJava基础之多线程【重点】

1.线程的基本知识及原理

1.1进程和线程

(1)进程概念:

正在运行的程序。进程是处于正在运行状态的程序,具备一定的独立功能。

(2)线程

是一个进程的一个执行单元,负责当前进程中程序的执行。

一个进程中至少有一个线程,一个进程可以是多个线程,这个应用程序因此被称为多线程程序。

简而言之:一个程序运行后至少有一个进程,一个进程中可以包含多个线程。

(3)线程的概念深入

什么是多线程?

即就是一个程序中有多个线程在同时执行。

一个核心的CPU在多个线程之间进行着随即切换动作,由于切换时间很短(毫秒甚至是纳秒级别),导致我们感觉不出来。

(4)java程序必有的线程:主线程Main

1.2线程执行的随机性/线程的组成

由于Cpu分时间片交替运行,宏观并行,微观串行。

线程的组成:

1.CPU    OS(操作系统负责调度)

2.数据    堆空间共享,栈空间独立

3.代码    实现Runnable接口,将代码实现在run方法中

1.3实现线程的两种方法:

(1)继承Thread类

步骤:

1.继承Thread类

2.覆盖run()方法

3.创建Thread对象,调用Thread对象的start()方法

案例:

package exception.io.thread.alltest;

public class ThreadTest01 {
	public static void main(String[] args) {
		SubThread st01=new SubThread();
		SubThread st02=new SubThread();
		st01.start();
		st02.start();
		for (int i = 0; i < 100; i++) {
			System.out.println("main run"+i);
		}
	}
}
class SubThread extends Thread{
	public void run(){
		for (int i = 0; i < 50; i++) {
			System.out.println("subThread run"+i);
		}
	}
}

(2)实现Runnable接口

步骤:

1.实现Runnable接口 覆盖run()方法;

2.创建Runnable对象作为Thread的构造方法的实参;

3.创建Thread对象,开启线程start()。

案例:

package exception.io.thread.alltest;

public class ThreadImplementsRunnableTest01  {
	public static void main(String[] args) {
		Runnables r1=new Runnables();
		Thread t1=new Thread(r1);
		t1.start();
	}
}
class Runnables implements Runnable{
	public void run(){
		for (int i = 0; i < 100; i++) {
			System.out.println(Thread.currentThread().getName()+"线程"+i);
		}
	}
}

(3)匿名内部类实现线程

前提:继承或接口实现

new 父类或者接口(){

      重写抽象方法

}

案例:

public class ThreadDemo {
  public static void main(String[] args) {
    //继承方式  XXX extends Thread{ public void run(){}}
    new Thread(){
      public void run(){
        System.out.println("!!!");
      }
    }.start();
    
    //实现接口方式  XXX implements Runnable{ public void run(){}}
    
    Runnable r = new Runnable(){
      public void run(){
        System.out.println("###");
      }
    };
    new Thread(r).start();
    new Thread(new Runnable(){
      public void run(){
        System.out.println("@@@");
      }
    }).start();
    
  }
}

1.4线程的名称获取方法

//两种方式 一种常规 一种简便
		//1.
            Thread t=Thread.currentThread();
		System.out.println(t.getName());
        //2.
		//获取现在正在执行的线程
		System.out.println(Thread.currentThread().getName());

1.5线程的状态变化

1.6线程池原理及实现(SinceJDK1.5)

1.6.1线程池的作用:

1.用于共享线程资源,

2.避免线程重复创建和销毁,

3.同时控制并发上线。

1.6.2线程池的原理 :

1.在java中,如果每个请求到达就创建一个新线程,开销是相当大的。

2.在实际使用中,创建和销毁线程花费的时间和消耗的系统资源都相当大,甚至可能要比在处理实际的用户请求的时间和资源要多的多。

3.除了创建和销毁线程的开销之外,活动的线程也需要消耗系统资源。 如果在一个jvm里创建太多的线程,可能会使系统由于过度消耗内存或“切换过度”而导致系统资源不足。 为了防止资源不足,需要采取一些办法来限制任何给定时刻处理的请求数目,尽可能减少创建和销毁线程的次数,特别是一些资源耗费比较大的线程的创建和销毁,尽量利用已有对象来进行服务。 线程池主要用来解决线程生命周期开销问题和资源不足问题。通过对多个任务重复使用线程,线程创建的开销就被分摊到了多个任务上了,而且由于在请求到达时线程已经存在,所以消除了线程创建所带来的延迟。这样,就可以立即为请求服务,使用应用程序响应更快。另外,通过适当的调整线程中的线程数目可以防止出现资源不足的情况。

1.6.3线程池的实现:

package exception.io.thread.alltest;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolTest01 {
	public static void main(String[] args) {
		//调用工厂类的静态方法,创建线程池对象
		//返回线程池对象 是返回的接口
		ExecutorService es=Executors.newFixedThreadPool(10);
		//调用线程的实现类对象es中的方法submit提交线程任务
		//将实现runnable接口的实现类对象 传递给线程池
		es.submit(new RunnableThreadPool());
		es.submit(new RunnableThreadPool());
		es.submit(new RunnableThreadPool());
	}
}
class RunnableThreadPool implements Runnable{
	public void run(){
		System.out.println(Thread.currentThread().getName()+"线程提交任务");
	}
}

 

创建固定大小的线程:

ExecutorService es = Executors.newFixedThreadPool(int n);

创建变动长度的线程池:

ExecutorService es = Executors.newCachedThreadPool();  

1.6.4如何获取当前计算机的核心数?并行的线程数?

获得CPU的可用线程数:

Runtime.getRuntime().availableProcessors()

1.7实现线程的Callable接口方式(实现线程程序的第三种方式)

实现步骤:

1.工厂类 Executors静态方法newFixedThreadPool方法,创建线程池对象;

2. 线程池对象ExecutorService接口实现类,调用方法submit提交线程任务 submit(Callable c)。

案例:

package exception.io.thread.alltest;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class CallableThreadPoolTest01 {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		//创建线程池对象
		ExecutorService es=Executors.newFixedThreadPool(10);
		//提交线程的方法submit返回Future接口的实现类
		Future<String> f=es.submit(new ThreadPoolCallable());
		String s=f.get();
		System.out.println(s);
		es.shutdown();
	}
}
class ThreadPoolCallable implements Callable<String>{

	public String call() throws Exception {
		// TODO Auto-generated method stub
		return "abcd";
	}
}

2.多线程操作面临的问题及解决方案

2.1线程操作共享数据的安全问题

当多线程共同访问一个对象(临界资源)的时候, 如果破坏了不可分割的操作(原子操作),就会产生数据不一致的问题

2.2线程安全问题的引发原因

多线程并发访问同一个数据资源,【可能】会引发数据的泄露或垃圾问题

package exception.io.thread.alltest;

public class TicketsThreadTest01 {
	public static void main(String[] args) {
		TicketsThread tt01=new TicketsThread();
		Thread t01=new Thread(tt01);
		Thread t02=new Thread(tt01);
		Thread t03=new Thread(tt01);
		t01.start();
		t02.start();
		t03.start();
	}
}
class TicketsThread implements Runnable{
	//定义要出售的票源
	private int ticket =100;
	private Object obj=new Object();
	public void run(){
		while(true){
			if(ticket>0){
             try{
                Thread.sleep(10); //加了休眠让其他线程有执行机会
              }catch(Exception ex){}
				System.out.println(Thread.currentThread().getName()+"出售第"+ticket--);
			}
		}
	}
}

2.3同步代码块解决线程安全的问题

2.4JDK1.5新特性Lock接口

package thread.security.test;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ArrayListTest01 {
	public static void main(String[] args) {
		
	}
}
class MyArrayList{
	private ReadWriteLock rwl=new ReentrantReadWriteLock();
	private Lock r1=rwl.readLock();
	private Lock w1=rwl.writeLock();
	
	//影响集合中的数据  写方法
	public void add(Object o){
		w1.lock();
		
		w1.unlock();
	}
	public void add(int pos, Object o){
		w1.lock();
		
		w1.unlock();
	}
	public void set(int pos,Object o){
		w1.lock();
		
		w1.unlock();
	}
	//获取集合的数据 不会影响到集合中的任何数据 读方法
	public void get(){
		r1.lock();
		
		r1.unlock();
	}
	public void size(){
		r1.lock();
		
		r1.unlock();
	}
}

2.5将不安全的集合变成安全的集合

        //格式:
        //集合类型         集合名称 = Collections.synchronized+集合类型(集合名称);

package thread.security.test;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class CollectionSynchronizedTest01 {
	public static void main(String[] args) {
		//格式:
		//集合类型 		集合名称 = Collections.synchronized+集合类型(集合名称);
		
		//ArrayList不安全 -> 线程安全
		List list = new ArrayList();
		List l2=Collections.synchronizedList(list);
		
		//HashMap->线程安全
		Map map01=new HashMap();
		Map map02=Collections.synchronizedMap(map01);
		
		//HashSet->线程安全
		Set set01=new HashSet();
		Set set02=Collections.synchronizedSet(set01);
		
	}
}

猜你喜欢

转载自blog.csdn.net/erpang7/article/details/82083695