- 什么是进程
概念: 正在运行的程序,所占用的内存的空间资源 - 什么是线程
概述: 线程就是对于CPU的一条独立的执行路径
看成是一个进程中的,多个小程序的独立执行 - 实现多线程的第一种方式
线程这个事物,也被封装成对象.线程对象的描述类
java.lang.Thread
实现创建新线程步骤
定义类,继承Thread
重写Thread类run方法
创建Thread子类对象
调用的是Thread类的方法start
/*
* 创建新的执行线程
* 定义类继承Thread
* 重写run方法
* new Thread子类对象
* 调用父类方法start()
* start 开启线程
* JVM调用run
* 规范,不管让线程运行什么,请把代码写在run中
*/
class SubThread extends Thread{
public void run(){
for(int x = 0 ; x < 50 ;x++){
System.out.println("run.."+x);
}
}
}
public class ThreadDemo {
public static void main(String[] args) {
SubThread s = new SubThread();
s.start();
for(int x = 0 ; x < 50 ;x++){
System.out.println("main.."+x);
}
}
}
- 实现多线程第二种方式
实现接口方式 java.lang.Runnable
实现步骤
定义类,实现Runnable接口
重写抽象方法run
创建Thread类对象 ,在Thread类的构造方法中,
传递Runnable接口实现类对象
调用Thread类方法start
/*创建新的执行线程
* 定义类实现接口Runnable
* 重写run方法
* new 实现接口类对象
* 创建Thread类对象,传递Runnable实现类
* 调用父类方法start()
* start 开启线程
* JVM调用run
* 规范,不管让线程运行什么,请把代码写在run中
*/
public class RunnableDemo {
public static void main(String[] args) {
// new 实现接口类对象
RunnableIterface r = new RunnableIterface();
//创建Thread类对象,传递Runnable实现类
Thread t1 = new Thread(r);
Thread t2 = new Thread(r);
Thread t3 = new Thread(r);
//调用父类方法start()
t1.start();
t2.start();
t3.start();
}
}
class RunnableIterface implements Runnable{ //定义类实现接口Runnable
public void run() {//重写run方法
System.out.println(Thread.currentThread().getName()+"第二种线程方法~~");
}
}
5 实现线程的两种方式对比
继承Thread
实现Runnable接口
继承Thread,单继承
继承的方式,线程中数据被单个线程独享
实现接口方式,避免了单继承局限性
实现方式,线程中的数据被线程共享
6 同步技术
出现目的,解决线程操作共享数据的安全问题
关键字 synchronized
格式:
synchronized(任意对象){
线程操作的所有共享数据
}
平衡,速度和安全上,保证安全,牺牲速度
任意对象: 监视器 –> 同步锁 – > 锁
线程运行到同步代码块的时候,先判断,判断这个锁还有没有
如果没有,只能等在外面
如果这个所有,有,线程就获取到这个对象锁,进入同步运行
线程出去同步代码块后,对象锁在交还回去
没有锁的线程,不能进入同步执行
上列子~~!
/*
* 要求:
* 多线程技术,模拟储户在银行存钱
* 每次存储100元,分别在两个窗口存,每个窗口存3次
* 余额是0
* 存储的时候余额变化
* 100 200 300 400 500 600
* 一个是银行 存钱的功能
* 一个储户,调用银行的存钱功能,参数
*
* 方法add 代码全是线程共享数据
* 同步整个方法 synchronized加在方法的声明上
*
* 同步方法,同步函数,同步方法只能被一个线程调用,不调用完成,其他线程不能调用
* 同步方法有锁吗,肯定有锁 , 本类对象引用 this
*
* 静态同步方法中,肯定也有锁,锁是谁呢,锁必须是对象
* 对象就是自己类的 class文件 被JVM创建出来的这个对象
*
* 任何一个数据类型 ,JVM都会赋予他一个特别的属性 属性名字 class
* 静态方法中的同步锁,就是自己本类.class属性
*/
class Bank{
private static int sum = 0;
//private Object obj = new Object();
public static synchronized void add(int money){
//synchronized(Bank.class){
sum = sum + money;
System.out.println(sum);
//}
}
}
class Customer implements Runnable{
private Bank b = new Bank();
public void run(){
for(int x = 0 ; x < 3 ; x++){
b.add(100);
}
}
}
public class ThreadDemo9 {
public static void main(String[] args) {
Customer c = new Customer();
Thread t0 = new Thread(c);
Thread t1 = new Thread(c);
t0.start();
t1.start();
}
}
- 死锁
多个线程,抢夺同一个对象锁,造成程序假死现象
/*
* 多线程,争夺同一个对象锁资源,出现的假死
* 同步的嵌套技术实现
*/
//定义类,实现同步的嵌套
class Dead implements Runnable{
private boolean b;
Dead(boolean b){this.b=b;}
public void run(){
while(true){
//对变量b进行判断,如果b=true,同步嵌套
//线程先进入同步A锁,在进入同步B锁
if(b){
synchronized(LockA.locka){
System.out.println("if...locka");
synchronized(LockB.lockb){
System.out.println("if...lockb");
}
}
}
//变量的值b=false,同步嵌套
//线程先进入同步B锁,在进同步A锁
else{
synchronized(LockB.lockb){
System.out.println("else...lockb");
synchronized(LockA.locka){
System.out.println("else...locka");
}
}
}
}
}
}
public class ThreadDead {
public static void main(String[] args) {
Dead d1 = new Dead(true);
Dead d2 = new Dead(false);
Thread t1 = new Thread(d1);
Thread t2 = new Thread(d2);
t1.start();
t2.start();
}
}
//创建2个类,2个类的对象,作为锁使用
class LockA{
public static final LockA locka = new LockA();
}
class LockB{
public static final LockB lockb = new LockB();
}
线程通信
所有的线程,操作的共享数据,必须都同步
必须保证所有的同步使用的锁,唯一的
线程通信中的等待与唤醒机制
生产者生产完成后,需要等待,等待之前唤醒消费者线程
消费者线程打印完后,需要等待,等待之前唤醒生产者线程程序加了线程的等待和唤醒 Object类的方法 wait notify
抛出 IllegalMonitorStateException异常
无效的监视器状态异常
wait notify 必须有锁的支持
只有锁对象才能调用
/*
* 线程的通信
* 多线程针对同一个学生资源,采用不同类型的数据操作
* 一个线程,负责对学生资源的复制,另一个线程对学生资源负责打印值
*/
//定义学生类,资源对象,姓名,姓别成员即可
class Student {
String name;
String sex;
boolean flag ;
}
//定义生产者线程,负责对学生赋值
class Product implements Runnable{
private Student s ;
Product(Student s){this.s=s;}
public void run(){
int x = 0 ;
while(true){
synchronized(s){
//判断标记
if(s.flag){
try{s.wait();}catch(Exception ex){}
}
if(x%2==0){
s.name = "张三";
s.sex = "男";
}else{
s.name = "李四";
s.sex = "女";
}
x++;
//修改标记的值
s.flag = true;
//唤醒消费线程
s.notify();
}
}
}
}
//定义消费者线程,负责学生变成获取值
class Customer implements Runnable{
private Student s;
Customer(Student s){this.s=s;};
public void run(){
while(true){
synchronized(s){
//判断标记
if(!s.flag){
try{s.wait();}catch(Exception ex){}
}
System.out.println(s.name+"..."+s.sex);
//修改变量的值
s.flag=false;
//唤醒生产线程
s.notify();
}
}
}
}
public class ThreadDemo {
public static void main(String[] args) {
Student s = new Student();
//创建2个Runnable接口实现类
Product p = new Product(s);
Customer c = new Customer(s);
Thread t0 = new Thread(p);
Thread t1 = new Thread(c);
t0.start();
t1.start();
}
}
这个线程通信中包含了一个唤醒等待机制
线程中的一些小知识点(别小看哦)
为什么wait(),notify(),notifyAll()等方法都定义在Object类中
操作线程的,Thread,为什么不写在Thread类中,出现在Object类中
锁的问题,锁是任意对象,等待还是唤醒必须有锁的支持,只有锁对象才能调用
方法写了最顶层的父类中,任何子类对象,当作锁,都可以调用线程的方法了
Thread类方法sleep 和 Object方法wait有什么区别
sleep 不会释放对象锁
wait 释放对象锁,被唤醒,从新获取锁才能运行- 线程池
池技术 pool
有些操作,非常耗时好资源
创建新的线程
JAVA连接数据库服务器
程序开始的时候,创建出锁需要的线程,创建只有1次
容器中保存起来,从容器取出,运行完成后,线程不死,继续回到容器中等待
集合容器
ArrayList
add(t0);
add(t0);
add(t0);
Thread t =array. remove(0);
t.start();
add(t);
JDK5版本,添加使用线程池的功能,内置线程池的概念
工厂类, 负责创建需要的对象
Executors 类负责创建线程池的对象
全部都是静态方法,类名调用
static ExecutorService newCachedThreadPool() 创建新的线程池对象
返回的肯定是接口ExecutorService实现类的对象
static ExecutorService newFixedThreadPool(int nThreads) 创建新的线程池对象,传递int参数
线程池就有指定的线程个数static ExecutorService newSingleThreadExecutor() 创建线程池对象,池子里面只有1个线程
等同于newFixedThreadPool(1)ExecutorService 接口方法
submit(Runnable task) 用于执行线程池中的线程,线程去运行Runnable接口实现类的run方法
void run(){
}
Future 获取线程执行后的返回值Future
submit(Callable task) 用于执行线程池中的线程,运行的是Callable接口的实现类的方法- 线程池
/*
* 使用JDK5新特性,创建线程池,并且让线程运行起来
* 1. 使用Executors静态方法创建线程池对象
* 2. ExecutorService接口方法 submit执行线程
* submit(Runnable)
*
*/
class RunnableImpl implements Runnable{
public void run(){
System.out.println(Thread.currentThread().getName());
}
}
public class ThreadPoolDemo {
public static void main(String[] args) {
//使用Executors静态方法创建线程池对象,2个线程的池子
ExecutorService es = Executors.newFixedThreadPool(2);
//调用接口方法submit 传递Runnable接口实现类
es.submit(new RunnableImpl());
es.submit(new RunnableImpl());
//关闭线程池
es.shutdown();
}
}
实现线程的第三种方式
java.util.concurrent.Callable
实现Callable接口,重写call方法
call可以有返回值,可以抛出异常
第三种方式,出现的版本1.5
不要和Thread,Runnable,Callable只能作用在线程池里Future submit(Callable call)传递Callable接口实现类的对象
submit方法执行完毕后,可以获取到线程运行后的返回值
返回的是Future接口的实现类对象Future接口方法 get 可以获取到线程执行后的返回值结果
/*
* 实现线程的第三种方式,结合线程池使用
* 线程运行后的结果
*/
//定义类,实现Callable,重写call方法
class CallableImpl implements Callable<String>{
public String call()throws Exception{
System.out.println("执行了call方法");
return "abc";
}
}
public class ThreadPoolDemo1 {
public static void main(String[] args)throws Exception {
//Executors 静态方法创建线程池
ExecutorService es = Executors.newFixedThreadPool(1);
//ExecutorService方法submit运行线程
//submit方法,返回Future接口实现类对象
Future<String> f = es.submit(new CallableImpl());
String s = f.get();
System.out.println(s);
es.shutdown();
}
}
- 单例设计模式Single
实现思想: 保证一个类的对象,在内存中唯一性
这个是个很有趣的东西~~!
先来个饿汉式的~~!
/*
* 保证Single类,的对象在内存中是唯一性
* 私有构造方法
* 创建对象,是要调用构造方法
* 本类成员位置,创建自己类的对象
* 提供公共访问方式,外类获取对象
*
* 以下写法,成为单例模式 -- 饿汉式
*
*/
public class Single {
private Single(){}
private static Single s = new Single();
public static Single getInstance(){
return s;
}
}
再来个懒汉的~~!
/*
* 保证Single类的对象,在内存中的唯一性
* 懒汉式,对象的延迟加载
* 利用同步保证数据安全,利用双重if判断,提升程序的执行效率
*/
public class Single {
private Single() {
}
private static Single s = null;
public static Single getInstance() {
if (s == null) {
synchronized (Single.class) {
if (s == null)//这个if是绝对绝对不可以去掉
s = new Single();
}
}
return s;
}
}
然后就是一下线程的方法~~!
* Thread类的方法 setDaemon(boolean )true
* 线程标记为守护线程,必须在start之前使用
* 所有的线程,都是守护线程的时候JVM,就退出
*
* Thread类的方法 static yield 线程的让步
* * 等待该线程终止
*
* Thread类 join
* 执行join方法的线程,会一次性执行完毕
* 其他线程,等我执行完后,抢CPU资源
* 线程的控制方法
* Thread类的静态的方法sleep(long 毫秒值)
* 让执行的线程,在指定的毫秒内,休眠,时间到了,自己醒来继续执行
这个方法要自己try —catch ~~
线程的优先级
* 每个线程都有自己的优先级 1-10
* Thread类方法 int getPriority() 获取线程的优先级
* 优先级高,在用CPU的时间相对更多一些
*
* setPriority(int newPriority) 设置线程的优先级
* Thread类中,提供三个静态成员变量,说明优先级
如何获取,设置线程的名字
- 每个线程都有自己的名字
- Thread-0 -1 -2
-
- 获取线程名字
- Thread类方法 String getName()
- 在Thread类用,在Thread子类使用
-
- Thread类,有一个静态方法 currentThread()
- 返回当前正在运行的线程对象 Thread currentThread()
- 继续使用线程对象,调用getName方法获取名字
-
- 设置线程名字
- Thread类的方法 void setName(String name)设置线程名字
Thread类的构造方法(String name)
JDK5新特性,实现线程的加锁和释放锁
- java.util.concurrent.locks
- 接口Lock 实现类ReentrantLock
- 替代了同步代码块,同步方法的使用
- 接口方法: lock 获取锁 unlock释放锁
终止线程的2个方式
- 第一个方式 stop 过时
- 第二个方式 结束run就可以
-
- void interrupt() 中断线程
- 比喻:
- 线程 ->wait永久等待,没有任何线程唤醒你
- interrupt让等待线程停止
class Stop implements Runnable{
private boolean flag = true;
public void run(){
while(flag){
synchronized(this){
try{this.wait();}
catch(Exception ex){
ex.printStackTrace();
System.out.println("抓住异常");
flag = false;
}
System.out.println("run...");
}
}
}
public void setFlag(boolean flag){
this.flag =flag;
}
}
public class ThreadStop {
public static void main(String[] args)throws Exception {
Stop s = new Stop();
Thread t0 = new Thread(s);
t0.start();
Thread.sleep(5);
t0.interrupt();
// s.setFlag(false);
}
}
以上方法不分顺序~ !
还有线程池 线程组
*Thread类的方法 ThreadGroup getThreadGroup()
*获取线程组对象,返回值是ThreadGroup类的对象
*ThreadGroup类方法 String getName()组的名字
*
*ThreadGroup对线程进行分组管理
* 分组管理一起对一个组中的线程进行统一的设置
*
*ThreadGroup构造方法 传递字符串的组的名字
* 可以自己定义组名,传递给ThreadGroup类构造方法
*
*如何把线程放在线程组中
*Thread类构造方法 第一个参数传递的是线程组的对象
*第二个参数,传递的Runnable接口的实现类对象
- 使用JDK5新特性,创建线程池,并且让线程运行起来
-
- 使用Executors静态方法创建线程池对象
-
- ExecutorService接口方法 submit执行线程
- submit(Runnable)
线程这个只是点实在是太乱了~~总结的不好 多多包涵