12.2日笔记

要学习线程,由于线程以来与、于进程而存在,所以要先学习进程

 

1.      什么是进程:进程是系统分配资源调用的一个独立单位.

2.      多进程有什么意义:

(1)    现在目前计算机是一种多进程计算机,在做一件事的同时,还在做另一件事情

(2)    多进程是为了提高计算机CPU的使用率

3.      线程:线程是依赖进程存在的,一个线程相当于进程中某个任务

4.      多线程的意义:

一个进程中开启多个任务,每一个任务(线程),他们在互相抢占CPU的执行权(提高程序执行效率)

多线程抢占CPU的执行权:具有随机性!

 

 

 

多线程:一个程序执行的路径有多条

单线程:程序的执行路径只有一条

 

Jvm,java虚拟机是多线程程序吗?

是多线程程序,由于java虚拟机中自带一个垃圾回收器,来确保程序不会轻易的造成内存溢出!

垃圾回收器会开启一个垃圾回收线程,来确保程序不会内存异常,将不用的变量或者没有更多引用的独享来回收掉!

public class ThreadDemo{

public static void main(String [] args){
    System.out.println(new Object());
    System.out.println(new Object());
    System.out.println(new Object());
    System.out.println(new Object());
    //..中间创建很多对象
    System.out.println(new Object());
}
}

如何实现多线程程序?(重点)

    要实现多线程程序,必须创建一个进程

    创建进程于晓调用系统资源进行创建,但是java语言是不能直接调用系统资源

    C/C++语言是可以创建系统资源,然后使用java语言调C/C++已经封装好的东西

    Javaà类:Thread类

        并发和并行

            并发:指的是同一个时间点

            并行:指的是同一个时间段

        多线程程序实现方式1:

            (1)自定义一个类:MyTread继承自Thread类

            (2)在MyThread类中重写Thread类中的run():为什么重写run()

            (3)在主线程中,创建该类的实例对象,启动线程


 public class ThreadDemo{
            public static void main(String [] args){
                //创建线程实例对象
                MyThread mt = new MyThread();
                //启动线程
                //启动线程不是调用run()方法,start()方法是线程开始执行的方法
                //run()方法调用相当于调用了一个普通的方法,性会不会出现线程随机性,而start()方法调用,其实是通过调用线程中的run()方法来进行多个线程抢占CPU执行权
                mt.start();
                // java.lang.IllegalThreadStateException
//第二次启动线程,会出现:非法线程状态
// java.lang.IllegalThreadStateException
//当前mt线程已经启动了,不能重新启动了
mt.start();
mt.run();
mt.run();
MyThread mt1 = new MyThread();
MyThread mt2 = new MyThread();
//分别启动线程
mt1.start();
mt2.start();
                }
            }

如何获取线程名称?

Public finalString getName()返回该线程的名称

设置线程名称

Public finalvoid setName(String name)改变线程名称,使之与参数name相同

package work1;

public class ThreadDemo{
    public static void main(String [] args){
        //创建线程类实例
        //无参构造的形式
        //MyThread mt1 = new MyThread();
        //MyThread mt2 = new MyThread();
        //有参构造形式设置线程名称
        //MyThread mt1 = new MyThread("qixuan");
        //MyThread mt2 = new MyThread("zhuzhu");
        //设置线程名称方式:无参+setName(String name)方法
    	MyThread mt1 = new MyThread();
        MyThread mt2 = new MyThread();
        //public final void setName(String name)改变线程名称,使之与参数name相同
        mt1.setName("qixuan");
        mt1.setName("zhuzhu");
        System.out.println(Thread.currentThread().getName());
        //启动线程
        mt1.start();
        mt2.start();
    }
}
package work1;

public class MyThread {
	
	//无参构造
	public MyThread() {
		
	}

	//有参构造
	public MyThread(String name){
		super(name) ;
		}
	
	//my1和my2子线程都会执行这段代码,两个子线程在互相抢占CPU的执行权
	public void run(){
		for(int x = 0;x<200;x++){
			System.out.println(getName+":"+x);
		}
	}



}
public final voidjoin()throws InterruptedException 等待该线程终止。
public class JoinDemo {
	public static void main(String[] args) {
		 // 创建该线程的实例对象
		JoinThread jt1 = new JoinThread() ;
		JoinThread jt2 = new JoinThread() ;
		JoinThread jt3 = new JoinThread() ;
		
		//设置线程名称
		jt1.setName("RNG") ;
		jt2.setName("EDG") ;
		jt3.setName("LGD") ;
		
		//启动线程
		jt1.start() ;
		//设置线程等待该线程终止该方法必须要启动线程
		try {
			jt1.join() ;
		} catch (InterruptedException e) {
			//InterruptedException:中断异常
			e.printStackTrace();
		//等到线程 1终止		
jt2.start() ;
		jt3.start() ;
	}
}
public class JoinThread extends Thread {
		public void run() {
		//jt1,jt2,jt3
		for(int x = 0 ; x <100 ; x ++){
			System.out.println(getName()+":"+x);
			
		}
	}
}

2 public final intgetPriority()返回线程的优先级。

线程的优先级有哪些?

    默认优先级:5

 java.lang.Thread

       publicstatic final int MAX_PRIORITY 10  :最大优先级   优先级大的抢占到CPU的执行权大,并不代表就一定能抢到,因为线程的执行具有随机性!

       publicstatic final int MIN_PRIORITY 1   :最小优先级

//测试类
public class ThreadProrityDemo {
	
	public static void main(String[] args) {
		
		//创建该线程的实例
		//并且设置线程名称
		MyPriority mp1 = new MyPriority() ;
		MyPriority mp2 = new MyPriority() ;
		MyPriority mp3 = new MyPriority() ;
		
		//设置线程名称:无参构造+setName()方法
		
//		//获取线程的优先级
//		System.out.println(mp1.getPriority());//5
//		System.out.println(mp2.getPriority());//5
//		System.out.println(mp3.getPriority());//5
		
		mp1.setName("RNG") ;
		mp2.setName("EDG") ;
		mp3.setName("LGD") ;
		
		//给线程设置优先级
		mp1.setPriority(10) ;
		mp2.setPriority(1) ;
		
		//启动线程
		mp1.start() ;
		mp2.start() ;
		mp3.start() ;
	}
}


public class MyPriority extends Thread {
	public void run() {
		for(int x = 0 ; x <100 ; x ++){
			System.out.println(getName()+":"+x);
		}
	}
}

3 public static voidyield()暂停当前正在执行的线程对象,并执行其他线程。

//暂停当前线程执行其他线程,并不保证另一个线程就一定能抢占到CPU的执行权

public class YieldThreadDemo {	
	public static void main(String[] args) {
		//创建线程类对象
		YieldThread yt1 = new YieldThread() ;
		YieldThread yt2 = new YieldThread() ;
		//设置线程名称
		yt1.setName("RNG") ;
		yt2.setName("EDG") ;
		//启动线程
		yt1.start() ;
		yt2.start() ;
	}
}
public class YieldThread extends Thread {
		public void run() {
			//yt1,yt2
			for(int x =0 ; x <100 ; x ++){
				System.out.println(getName()+":"+x);
				Thread.yield() ;
			}
		}
}

4 public final voidsetDaemon(boolean on)  on指定true,就是设置守护线程.

 将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出。

    该方法必须在启动线程前调用。

    jvm自动退出,对于主线程的数据如果直接输出完毕,对于两个守护线程来说不会立即消失,Jvm等会就自动退出.

public classThreadDemaonDemo {
    public static void main(String[] args) {
       //创建线程类对象
       ThreadDeamon td1 = new ThreadDeamon() ;
       ThreadDeamon td2 = new ThreadDeamon() ;
      
       //设置线程名称
       td1.setName("rng") ;
       td2.setName("edg") ;
       td1.setDaemon(true) ;
       td2.setDaemon(true) ;
      
      
       //启动线程
       td1.start() ;
       td2.start() ;
      
       Thread.currentThread().setName("lgd") ;
       for(int x = 0 ; x <5 ; x++){
           System.out.println(Thread.currentThread().getName()+":"+x);
       }
    }
}
 
public class ThreadDeamonextends Thread {
       public void run() {
           for(int x = 0 ; x <100 ; x ++){
              System.out.println(getName()+":"+x);
           }
       }
}

5  线程睡眠:public static voidsleep(long millis)

throws InterruptedException在指定的毫秒数内让当前正在执行的线程休眠(暂停执行

public class ThreadSleepDemo {
	public static void main(String[] args) {
		//创建线程类对象
		ThreadSellp ts1 = new ThreadSellp() ;
		ThreadSellp ts2 = new ThreadSellp() ;
		ThreadSellp ts3 = new ThreadSellp() ;
		//设置线程名称
		ts1.setName("线程1") ;
		ts2.setName("线程2") ;
		ts3.setName("线程3") ;
		//启动线程
		ts1.start() ;
		ts2.start() ;
		ts3.start() ;
	}
}
import java.util.Date;
public class ThreadSellp extends Thread {
	public void run() {
		//ts1,ts2,ts3
		for(int x = 0 ; x <100 ; x ++){
			System.out.println(getName()+":"+x+",日期:"+new Date());
			//睡眠1秒中
			try {
				Thread.sleep(1000) ;//此方法本身就抛出一个异常!
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

6  线程停止:

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

public void interrupt()中断线程,表示中断线程一种状态


public class ThreadStopDemo {
	public static void main(String[] args) {
		//创建线程类对象
		ThreadStop ts = new ThreadStop() ;
		ts.start() ;
		try {
			ts.stop() ;//该方法表示过时,但是可以用它
			//强迫线程停止执行
			ts.interrupt() ;//中断一种状态
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
}


多线程实现的第二种方式:(实际开发中第二种比第一种应用更广泛)

 开发步骤:

 1)自定义一个类MyRunnable,该类实现Runnable接口

 2)实现该接口中的run()方法

 3)在主线程中创建该类的实例对象,

 4)创建Thread类对象,将3)创建的这个对象作为参数进行传递

 5)分别启动线程

面试题:多线程的实现方式有几种,分别是什么?

三个方式,分别阐述

第三种:和线程池有关系(并且和Callable接口有关系)

 

public class ThreadDemo {
	public static void main(String[] args) {
		//1)创建MyRunnable实例对象
		MyRunnable my = new MyRunnable() ;
		//2)创建线程类对象
		//Thread线程类中的构造方法
		//public Thread(Runnable target)
		//public Thread(Runnable target,String name)
		Thread t1 = new Thread(my, "线程1") ;
		Thread t2 = new Thread(my, "线程2") ;
		//启动线程
		t1.start() ;
		t2.start() ;
	}
}


public class MyRunnable implements Runnable {
	//run()中的方法也是需要一些耗时的操作
	public void run() {
		for(int x = 0 ; x < 100 ; x ++){
			//在控制台,打印每一个子线程的线程名称
			//getName()是Thread类中的方法
			//间接的使用Thread类的静态功能得到线程名称
		System.out.println(Thread.currentThread().getName()+":"+x);
		}
	}

}

课堂练习 

 某电影院目前正在上映贺岁大片(红高粱,少林寺传奇藏经阁),共有100张票,而它有3个售票窗口售票,请设计一个程序

模拟该电影院售票。

  继承自Thread类


public class SellTicketDemo {
	public static void main(String[] args) {
		//创建线程类对象
		SellTicket st1 = new SellTicket() ;
		SellTicket st2 = new SellTicket() ;
		SellTicket st3 = new SellTicket() ;
		//分别命名三个窗口
		st1.setName("窗口1") ;
		st2.setName("窗口2") ;
		st3.setName("窗口3") ;
		//启动线程
		st1.start() ;
		st2.start() ;
		st3.start() ;
		
	}
} 
public class SellTicket extends Thread {
	//这100张票应该被三个线程共用,所以用static修饰
	private static int tickets = 100 ;
	public void run() {
		//st1,st2,st3都要执行run()方法中代码
//将这个代码放到run()方法的外面)
		while(true){
			if(tickets>0){
				System.out.println(getName() + "正在出售第" + (tickets--) + "张票");
			}
		}
	}
}


public class SellTicket implements Runnable {
	
	private  static int tickets = 100 ;
	public void run() {
// 模拟电影院一直有票
	while (true) {	
//设置线程睡眠0.1m
if (tickets > 0) {
//ts1,ts2,ts3
try {
Thread.sleep(100) ;
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在出售第"
						+ (tickets--) + "张票");
			}
		}
	}
	
//一张票可能会被卖多次,(加入延迟操作之后)
	public void run() {
// 模拟电影院一直有票
	while (true) {
		//设置线程睡眠0.1m
			if (tickets > 0) {
//ts1,ts2,ts3
				try {
					Thread.sleep(100) ;
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName() + "正在出售第"+ (tickets--) + "张票");
/			}

多个线程在抢占CPU的执行权,CPU的一点点时间片具有特性:原子性操作(最简单最基本):比如变量++或者--

窗口1正在出售100张票

 ticketss--,之前的动作:记录之前的值100(窗口2)

窗口2在记录值的时候抢占cPU的执行权,打印-->窗口也正在出售第100张票

public void run() {
		// 模拟电影院一直有票
		while (true) {
			//设置线程睡眠0.1m
			//ts1,ts2,ts3
			try {
				Thread.sleep(100) ;
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			if (tickets > 0) {
				System.out.println(Thread.currentThread().getName() + "正在出售第"+ (tickets--) + "张票");
			}
			 
		}
	}

}

接口:自定义类实现Runnable接口(研究主要接口的形式)

为了模拟电影院卖票更真实的场景,每一个窗口卖票应该延迟操作

在接口自实现类中,在run()方法中让每一个线程执行睡眠0.1秒

加入延迟操作:

1)一张票可能被卖多次

100张票会出现多次

CPU的执行具有原子性操作

2)可能出现负票,延迟操作和线程随机性导致

这两种情况都属于线程安全问题,现在写的这个代码是一种有问题的代码?

检验多线程安全问题的标准(以后在判断一个多线程序是否有安全问题的标准)

1)当前是否是一个多线程环境

2)多线程环境中是否有共享数据

3)是否有多条语句对共享数据进行操作

优化改进:

将多条语句对共享数据进行操作的代码用代码块包起来

使用同步代码块:synchronized(同步锁对象){

多条语句对共享数据的操作;

同步锁对象:应该每一个线程都要使用这个锁对象(同步锁):理解为门的开和关

使用同步代码块可以解决线程安全问题

同步锁对象可以是什么样的对象?

可以是Object类型,任意的Java类


public class SellTicketDemo {
	public static void main(String[] args) {
		//创建SellTicket对象
		SellTicket st = new SellTicket() ;
		//创建线程类的对象
		Thread t1 = new Thread(st, "窗口1") ;
		Thread t2 = new Thread(st, "窗口2") ;
		Thread t3 = new Thread(st, "窗口3") ;
		//启动线程
		t1.start() ;
		t2.start() ;
		t3.start() ;
	}
}

public class SellTicket implements Runnable {
	//100张票被共用,不让外界修改数据
	private  static int tickets = 100 ;
	//同步锁对象
//	private Object obj = new Object() ;
	private Demo d = new Demo() ;
	public void run() {
		// 模拟电影院一直有票
		while (true) {
			//设置线程睡眠0.1m
			//ts1,ts2,ts3
			//相当于ts1,ts2,ts3创建自己的锁定(不是同一把锁)
//synchronized(new Object()){
			synchronized(d){//每一个线程ts1,ts2,ts3都使用的一个锁
				//ts1进来,其他线程进不来
				if (tickets > 0) {
					try {
						Thread.sleep(100) ;
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				System.out.println(Thread.currentThread().getName() + "正在出售第"+(tickets--) + "张票");
				}
			}//ts1出来了
		}
	}

}
class Demo{
	
}




public class SellTicket implements Runnable {
	//100张票被共用,不让外界修改数据
	private  static int tickets = 100 ;
	//同步锁对象
	private Object obj = new Object() ;
	public void run() {
		//t1,t2,t3子线程要执行循环语句中的内容
		while (true) {
			//t1线程先抢占CPU的执行权
			//理解为门的开和关
			//t1,t2,t3继续抢占CPU的执行权
			//t2抢占到了,门一关,t1,t3进不来了
			synchronized(obj){//t1进来,门关了,t2和t3线程都不会进来
				if (tickets > 0) {
					try {
						Thread.sleep(100) ;
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName() + "正在出售第"+ (tickets--) + "张票");
//窗口1正在出售第100张
//窗口正在出售第99张
		}
		}//代码执行完毕,t1线程出来,意味着门开了...  
  
		
		}
	}

}

静态同步方法:要通过反射获取Class类对象(当前类的字节码文件对象)

对于非静态同步方法来说,它的同步锁对象是this

public void run() {
		while (true) {
			if(x%2==0){
				synchronized(SellTicket.class){//静态同步方法:要通过反射获取Class类对象(当前类的字节码文件对象)
					if (tickets > 0) {
						try {
							Thread.sleep(100) ;
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
						System.out.println(Thread.currentThread().getName() + "正在出售第"
								+ (tickets--) + "张票");
						//窗口1正在出售第100张
						//窗口正在出售第99张
					}
				}
			}else{
				
				sellTicket() ;
				
			}
			x ++ ;
		}
	}

同步锁定对象:

1)可以Object类型以及任意的Java类型对象

2)如果一个方法进来之后是一个同步代码块,那么同步代码块可以演变成一个同步方法

3)如果是一个静态的同步方法,锁对象是当前类名class属性:类名.class (反射机制:获取一些类的字节码文件对象Class类对象)

面试题:

wait()线程等待,notify(),唤醒单个线程,notifyAll():唤醒所有线程这三个方法为什么不定义到Thread类中呢,而是定义在Object类中?

线程中会存在安全问题,并且解决线程安全问题使用的同步代码块或者同步方法来解决,同步代码块来解决线程安全问题,就存在

同步锁对象,谁能代表同步锁对象(Object以及任意的Java类),把它定义到Object类中;

等待唤醒机制(生产者和消费者线程)

 

 

 线程安全的类有哪些?

 Vector

 StringBuffer

 Hasttable

public class ThreadDemo {
	public static void main(String[] args) {
		//1)集合里面的Vector集合
		Vector<String> v = new Vector<String>() ;
		//2)字符串缓冲区
		StringBuffer sb = new StringBuffer("StringHello") ;
		//3)Map集合中的子实现类:Hashtable
		Hashtable<String, String> hm = new Hashtable<String,String>() ;
		//从集合中来看,vector集合是一个安全的类,实际开发也不怎么用它
		//Collections:针对集合操作的工具类
		//public static <T> List<T> synchronizedList(List<T> list)返回指定列表支持的同步(线程安全的)列表
		ArrayList list = new ArrayList() ;
		List l = Collections.synchronizedList(list) ; //安全的集合列表
	}
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值