黑马程序员————java多线程及同步机制

------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------

  

1.理解程序、进程、线程的概念
程序可以理解为静态的代码,计算机指令的集合,它以文件的形式存储在磁盘上。
进程可以理解为执行中的程序,一个单独程序打开了单独的一段地址空间进行单独的工作。
线程可以理解为进程的进一步细分,程序的一条执行路径。

多线程并非是指许多个线程同时运行,而是cpu的快速切换。

线程大致的粗分为五个状态:

创建  通过 new Thread及其子类

运行   正在执行的线程,占据cpu

阻塞   拥有执行资格,只是没有抢到cpu,这是随机的有cpu决定

冻结   无执行资格,处于休眠状态

消亡   run方法执行完毕(1.5以前可以通过调用stop方法来强制结束线程)

线程实质是由Windows来创建,而java已经将创建线程这一功能封装好了,只需要用就可以了,继承java.lang包中的Thread类即可。大致分为两种方法

方法一:直接继承Thread类

class PrintNum extends Thread{//继承Thread类
	public void run(){
		//复写run方法,子线程执行的代码
		for(int i = 1;i <= 100;i++){
			if(i % 2 == 0){
				System.out.println(Thread.currentThread().getName() + ":" + i);
			}
		}
	}
	public PrintNum(String name){
		super(name);
	}
}

public class TestThread {
	public static void main(String[] args) {
		PrintNum p1 = new PrintNum("线程1");
		PrintNum p2 = new PrintNum("线程2");
		p1.setPriority(Thread.MAX_PRIORITY);//优先级10
		p2.setPriority(Thread.MIN_PRIORITY);//优先级1
		p1.start();//启动线程并调用run方法
		p2.start();
	}
}

  分为三个步骤:1.创建线程  2.复写Tread中的run方法,也就是把要执行的代码块放其中 3.调用stat方法,启动线程并调用run方法

方法二:实现Runnable接口

class SubThread implements Runnable{
	public void run(){//2.复写run方法
		//子线程执行的代码
		for(int i = 1;i <= 100;i++){
			if(i % 2 == 0){
				System.out.println(Thread.currentThread().getName() + ":" + i);
			}
		}
	}
}
public class TestThread{
	public static void main(String[] args){
		SubThread s = new SubThread();
		Thread t1 = new Thread(s);//1.创建线程
		Thread t2 = new Thread(s);

		t1.setName("线程1");
		t2.setName("线程2");

		t1.start();//3.启动并调用run方法
		t2.start();
	}
}

  

两种方法的比较:

如果没有该类没有继承其他类则用继承方法,run方法是写在Thread类中,而且对于一大段代码中出现过的多次循环体也直接采用匿名内部类将其包装起来实现多线程比较简洁

new Thread(){
     public void run(){
          for(int i=0;i<100;i++){
               System.out.println(i);
          }
     }
}.start();

但是单继承具有局限性,如果多个线程有共享数据的话,建议使用实现方式,同时,共享数据所在的类可以作为Runnable接口的实现类,run方法是写在Runnable接口中。比如,两个窗口同时买100张票。

class gxzy implements Runnable{//实现Runnable接口
	private int piao=100;
	public void run(){//重写run方法
		while(true){
			if(piao>0)
			System.out.println(Thread.currentThread().getName()+"  第"+piao--+"票");
			}
		}
	}
public class maipiao {
	public static void main(String[] args){
		gxzy gx = new gxzy();
		Thread xz1 =new Thread(gx);//创建线程
		Thread xz2 =new Thread(gx);
		xz1.setName("第1号买票窗口");
		xz2.setName("第2号买票窗口");
		xz1.start();//启动线程并调用run方法
		xz2.start();

	}
}

  但是上面的程序有个安全问题存在,即如果在线程运行到if语句之下还未执行输出语句时,cpu被其他程序(是程序哦)给占了,那么此线程处于阻塞状态,而其他线程排在后面,当这个线程恢复为运行状态时刚好卖出的是最后一张票,则有可能后面的线程会卖出第0张票,写一个sleep方法就可以清晰的看到问题所在了

class gxzy implements Runnable{
	private int piao=100;
	Object obj = new Object();
	public void run(){
		while(true){
			if(piao>0)
				try{
					Thread.sleep(3);//停3毫秒
					}
				catch(Exception e){

				}
				System.out.println(Thread.currentThread().getName()+"  第"+piao--+"票");
			}
		}
	}

  那么这个时候就需要采用同步来解决了,同步提供一个锁,在这个线程执行run方法的时候锁会关上,其他线程是无法进去的,直到这个线程执行完毕锁打开,其他线程才能呢进来。

synchronized关键字为同步,有两种写法可以写出同步代码块,里面的锁可以是任意对象,一般采用object类或现有资源类

synchronized(对象){执行的代码块}

  还有一种是用synchronized修饰在函数上的称为同步函数,也就是把那想要同步的代码块单独拿出来写在一个方法里,再用synchronized修饰。这里的锁是this,如果函数经static修饰,因为静态里不能有this也先于对象存在所以他的锁为java.class字节码文件对象,格式为 类名.class。

无论是同步代码块还是同步代码函数,使用时都有两个前提,有两个或以上的线程,多个线程使用同一个锁。

 

看看单例模式中的懒汉式,用同步解决他的线程问题

class aa{
	private static aa bb =null;
	private aa(){}
	public static aa lei(){
		if(bb==null);//双重判断,提高效率
		synchronized(aa.class){//创建了对象之后,将拒绝所有线程的访问
		 if(bb==null){
			 bb=new aa();
		 }
			return bb;
		}
	}
}

  我们没有用同步函数而是用的代码块,这样更灵活一些,如果直接采用同步函数,将十分低效,即使是当创建了对象也会不断有线程进来访问锁,而锁的一大弊端是很耗费资源。而采用代码块使用双重判断,在锁前面来一个判断,则不需要再对锁进行访问了。还有一点值得注意的还返回对象的函数是静态的,而静态的锁为类名.class。

时间: 2024-10-05 23:27:06

黑马程序员————java多线程及同步机制的相关文章

黑马程序员---Java多线程

---------------------- Android开发.java培训.期待与您交流! ---------------------- 线程与进程是程序运行中体现的两个名词,它包含这不同的程序域.进程指的是一个正在运行的程序,如:360,QQ运行时就是不同的两个进程.当你打开windows任务管理器时,看到的每个进程就是此时windows中正在运行的程序.线程则就是进程中的一个个独立的控制单元,线程控制着进程的执行,也就是说每个正在运行的程序中就包括着很多的线程. 主线程:Java虚拟机运

黑马程序员——Java多线程基础知识2

多线程协同 线程间的通讯:我们对资源的操作动作不同,比如说两个卡车一个拉煤一个装煤.但是他们共享了一个资源. 怎么样把这个资源拿出来?怎样把车装满?这个资源当然是一个类,他里面的组成元素就是对象!!现在我们就要有操作对象的思想了,我用对象把这车装满,现在一车装一个对象. 等待唤醒机制: 用的不是sleep是wait.flag标记,这是两人沟通的方式.其实每个标记就要做一次等待或者notify,判断wait,改值notify.线程池.notify唤醒里面的线程,按顺序唤醒.wait和notify必

黑马程序员——java多线程基础知识1

多线程 进程是一个正在执行的程序. cpu在同时执行这些程序,其实是跳跃式的,做快速的切换,时间很短.一个进程可能存在多条路径.迅雷的多路径.每一个进行执行都有一个执行顺序,该顺序是一个执行路径,或这叫一个控制单元.每一个进程至少有一个线程,线程就是进程中的一个独立的控制单元,线程控制进程的执行.jvm启动的时候会有一个进程就叫做java,exe,该进程中至少有一个线程在控制Java程序的执行 ,而且该线程的执行代码在 主函数中.该线程称为主线程.虚拟机至少也有两个线程,一个主线程执行,另一个负

黑马程序员——Java多线程

多线程基础知识 进程是一个正在执行的程序. cpu在同时执行这些程序,其实是跳跃式的,做快速的切换,时间很短.一个进程可能存在多条路径.迅雷的多路径.每一个进行执行都有一个执行顺序,该顺序是一个执行路径,或这叫一个控制单元.每一个进程至少有一个线程,线程就是进程中的一个独立的控制单元,线程控制进程的执行..jvm启动的时候会有一个进程就叫做java.exe,该进程中至少有一个线程在控制Java程序的执行 ,而且该线程的执行代码在 主函数中.该线程称为住线程.虚拟机至少也有两个线程,一个主线程执行

黑马程序员-JAVA多线程总结

------<a href="http://www.itheima.com" target="blank">Java培训.Android培训.iOS培训..Net培训</a>.期待与您交流! ------- JAVA多线程实现方式主要有三种:继承Thread类.实现Runnable接口.使用ExecutorService.Callable.Future实现有返回结果的多线程.其中前两种方式线程执行完后都没有返回值,只有最后一种是带返回值的.

黑马程序员-Java多线程《四》

                         ------- android培训.java培训.期待与您交流! ---------- 1.线程和进程的概念 1.1.进程(Process):拥有独立的内存空间,每个独立执行的程序称为进程   1.2.线程(Thread):线程是一个程序内部的一条执行路径,Java虚拟机允许应用程序并发地运行多个执行线程   1.3.线程和进程的区别           每个进程都有独立的代码和数据空间(进程上下文),进程间的切换开销大           线程

黑马程序员-Java多线程操作

--Java培训.Android培训.iOS培训..Net培训.期待与您交流!--- Java中的线程 一个程序的运行需要启动一个应用进程,一个进程可以创建多个线程,帮助应用完成多任务操作,实现并发运行.在Java中线程是被封装成Thread类,进行多线程操作时只需要继承一个Thread类,实现自己的功能即可,然后开启此线程,或者你也可以实现一个Runnable接口,然后将其传递给Thread对象,然后再启动它. 线程的创建于启动 继承Thread 创建一个类并继承Thread类,然后实现Thr

黑马程序员-Java多线程篇《四》

                         ------- android培训.java培训.期待与您交流! ---------- 1.线程和进程的概念 1.1.进程(Process):拥有独立的内存空间,每个独立执行的程序称为进程   1.2.线程(Thread):线程是一个程序内部的一条执行路径,Java虚拟机允许应用程序并发地运行多个执行线程   1.3.线程和进程的区别           每个进程都有独立的代码和数据空间(进程上下文),进程间的切换开销大           线程

黑马程序员---Java多线程的用法详解

------- android培训.java培训.期待与您交流! ---------- Java线程详解 一.操作系统中线程和进程的概念 现在的操作系统是多任务操作系统.多线程是实现多任务的一种方式. 进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程.比如在Windows系统中,一个运行的exe就是一个进程. 线程是指进程中的一个执行流程,一个进程中可以运行多个线程.比如java.exe进程中可以运行很多线程.线程总是属于某个进程,进程中的多个线程