`
airfly2013
  • 浏览: 18695 次
最近访客 更多访客>>
社区版块
存档分类
最新评论

黑马程序员 java_多线程(一)

 
阅读更多

                                     

                        ------- android培训java培训、期待与您交流! ----------

 

多线程

 

 

 

 基本理解

 

进程:是一个正在执行中的程序。每一个进程执行都有一个执行顺序。该顺序是一个执行路径,或者叫一个控制单元。
线程:就是进程中的一个独立的控制单元。线程在控制着进程的执行。一个进程中至少有一个线程。
 
Java VM  启动的时候会有一个进程java.exe.该进程中至少一个线程负责java程序的执行。而且
这个线程运行的代码存在于main方法中。该线程称之为主线程。此外还会启动负责垃圾回收机制的线程。
 
可以简单理解为:进程是需要执行的任务,而线程是cpu能够同时执行的最大任务数量。在一台电脑中线程数量有cpu决定,是固定的。而进程是由需要执行的任务决定,数量是变动的。在个人电脑中,一般会有几十个进程,只有几个线程(有的甚至只有一个线程),为了保证所有任务得到执行,cpu就需要在这些任务上不到切换,切换速度相当快,就好像几十个任务一起执行的。
 
java中的多线程技术与cpu上的多线程是不同的,首先cpu的多线程是从物理上来说,有几个运行核,就可以同时运行几个任务。而java中的多线程技术是相对于逻辑上来说的,我有几个线程需要独立运行,看上去还要"同时"运行,实际上它们并没有同时运行,它们在不停争夺cpu执行资格,这也是为什java多线程中往往线程需要等待以便获取cpu执行权,然后才能执行代码。它们只是在相对独立的运行,并且运行顺序上不分先后。这其实就有点像windows操作系统上多个进程“同时”执行一样。
 
java多线程技术是非常有用的,首先可以提供代码运行速度。此外一些程序中需要两段甚至更多代码的交互运行,多线程技术将能很好的解决这个问题。

 

 

 

    定义线程

 

有两种方法,第一种为:继承Thread类

通过对api的查找,java已经提供了对线程这类事物的描述。就Thread类。

 

 步骤:  1,定义类继承Thread。

               2,复写Thread类中的run方法。

                     目的:将自定义代码存储在run方法。让线程运行。

               3,调用线程的start方法。

                     该方法两个作用:启动线程,调用run方法。

 

 


class Demo extends Thread
{
	public void run()
	{
		for(int x=0; x<60; x++)
			System.out.println("demo run----"+x);
	}
}


class ThreadDemo 
{
	public static void main(String[] args) 
	{
		//for(int x=0; x<4000; x++)
		//System.out.println("Hello World!");

		Demo d = new Demo();//创建好一个线程。
		//d.start();//开启线程并执行该线程的run方法。
		d.run();//仅仅是对象调用方法。而线程创建了,并没有运行。

		
		for(int x=0; x<60; x++)
			System.out.println("Hello World!--"+x);
		
	}
}

可以发现运行结果每一次都不同。这是因为多个线程都获取cpu的执行权。cpu执行到谁,谁就

运行。

  

在定义线程是需要复写run()方法,这是因为:

Thread类用于描述线程。该类就定义了一个功能,用于存储线程要运行的代码。该存储功能就

是run方法。也就是说Thread类中的run方法,用于存储线程要运行的代码。

 

    创建线程的第二种方式:实现Runable接口

 

          步骤:1,定义类实现Runnable接口

                       2,覆盖Runnable接口中的run方法。将线程要运行的代码存放在该run方法中。

                       3,通过Thread类建立线程对象。

                       4,将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数。

                             为什么要将Runnable接口的子类对象传递给Thread的构造函数。

                                    因为,自定义的run方法所属的对象是Runnable接口的子类对象。

                                    所以要让线程去指定指定对象的run方法。就必须明确该run方法所属对象。

                       5,调用Thread类的start方法开启线程并调用Runnable接口子类的run方法

 

package itcast.heima;

class Ticket implements Runnable
{
	private  int tick = 100;
	public void run()
	{
		while(true)
		{
			if(tick>0)
			{
				System.out.println(Thread.currentThread().getName()+"....sale : "+ tick--);
			}
		}
	}
}

class  TicketDemo
{
	public static void main(String[] args) 
	{

		Ticket t = new Ticket();

		Thread t1 = new Thread(t);//创建了一个线程;
		
		t1.start();
		
	}
}

 

       

 

这部分也可以这么理解,Runnable接口提供了定义线程的内容格式,这些内容都定义在了run()方法

中,Thread类提供了创建线程的方式。

 

 首先Runnable接口提供了定义线程的内容格式

因为Thread类已经实现了Runnable接口,所以当我们通过Thread子类创建对象时,Thread子类

的run方法会复写Runnable接口中的run()方法。

 

 Thread类提供了创建线程的方式

从上面两个例子可以看出无论通过Thread子类的方式定义线程,还是通过实现Runnable接口的方式,最终都需要Thread来创建线程。

 

由于用继承方式创建代码避免了单继承的局限性,所以在定义线程时,建议使用实现Runnable的方法。

 

 

 

   线程的四种状态

 




 
 

 

 

      同步

 

 

    多线程的运行时,往往会出现我们不想看到的结果。


class Ticket1 implements Runnable
{
	private  int tick = 100;
	public void run()
	{
		while(true)
		{
			if(tick>0)
			{
				System.out.println(Thread.currentThread().getName()+"....sale : "+ tick);
				tick--;
			
			}
		}
	}
}


class  TicketDemo
{
	public static void main(String[] args) 
	{

		Ticket1 t = new Ticket1();

		Thread t1 = new Thread(t);
		Thread t2 = new Thread(t);
		Thread t3 = new Thread(t);
		Thread t4 = new Thread(t);
		t1.start();
		t2.start();
		t3.start();
		t4.start();

	}
}

 



 

从结果中可以看到,打出来四张编号为100的票,出现的原因是,当线程t1刚打印了标号为100的票,还没有执行tick--,线程t2和t3还要t4都接着执行打印编号的语句。所以都打印了编号为100的票,这显然不是设计程序时想要的结果。这就是多线程安全问题。

 

问题的原因:

当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行

完,另一个线程参与进来执行。导致共享数据的错误。归根到底还是因为是由cpu不断的快速切

换造成的。

 

解决办法:

对多条操作共享数据的语句,只能让一个线程都执行完。在执行过程中,其他线程不可以参与

执行。

 

 

同步代码块

 

Java对于多线程的安全问题提供了专业的解决方式,就是同步代码块。

            synchronized(对象)

                   {

                            需要被同步的代码

                    }

对象如同锁。持有锁的线程可以在同步中执行。没有持有锁的线程即使获取cpu的执行权,也进

不去,因为没有获取锁。

 

         同步的前提:

                1,必须要有两个或者两个以上的线程。

                2,必须是多个线程使用同一个锁。

                必须保证同步中只能有一个线程在运行。

 

           好处:解决了多线程的安全问题。

           弊端:多个线程需要判断锁,较为消耗资源,


class Ticket implements Runnable
{
	private  int tick = 1000;
	Object obj = new Object();
	public void run()
	{
		while(true)
		{
			synchronized(obj)
			{
				if(tick>0)
				{
					System.out.println(Thread.currentThread().getName()+"....sale : "+ tick--);
				}
			}
		}
	}
}


class  TicketDemo2
{
	public static void main(String[] args) 
	{

		Ticket t = new Ticket();

		Thread t1 = new Thread(t);
		Thread t2 = new Thread(t);
		Thread t3 = new Thread(t);
		Thread t4 = new Thread(t);
		t1.start();
		t2.start();
		t3.start();
		t4.start();


	}
}

同步以后,同步代码块中只能同时运行一个线程,就不会出现安全问题,就不会买出现,零和

负数的票。

 

 

同步函数

 

将关键字sychronized修饰函数,即可创建同步函数。

格式为:

             public synchronized void show(){}

 

同步函数用使用的锁     

              同步函数使用的锁是this。

              静态的同步方法,使用的锁是该方法所在类的字节码文件对象。 类名.class

 

 

同步的好处:

       解决了线程的安全问题。

 

弊端:

较为消耗资源。

同步嵌套后,容易死锁。

 

 

 

 

死锁

 

 

简单的就是说,同步中嵌套同步。 

class Test implements Runnable
{
	private boolean flag;
	Test(boolean flag)
	{
		this.flag = flag;
	}

	public void run()
	{
		if(flag)
		{
			while(true)
			{
				synchronized(MyLock.locka)
				{
					System.out.println(Thread.currentThread().getName()+"...if locka ");
					synchronized(MyLock.lockb)
					{
						System.out.println(Thread.currentThread().getName()+"..if lockb");					
					}
				}
			}
		}
		else
		{
			while(true)
			{
				synchronized(MyLock.lockb)
				{
					System.out.println(Thread.currentThread().getName()+"..else lockb");
					synchronized(MyLock.locka)
					{
						System.out.println(Thread.currentThread().getName()+".....else locka");
					}
				}
			}
		}
	}
}


class MyLock
{
	static Object locka = new Object();
	static Object lockb = new Object();
}

class  DeadLockTest
{
	public static void main(String[] args) 
	{
		Thread t1 = new Thread(new Test(true));
		Thread t2 = new Thread(new Test(false));
		t1.start();
		t2.start();
	}
}

 



可以看出程序并未结束,而是处于不能继续往下执行就状态。从上面代码可以看出,线程t1将先拿锁 locka,然后拿lockb。而线程t2会先拿锁lockb,然后拿locka。

从结果中看出,线程t2拿锁lockb,正在等待锁locka被释放,而此时线程t1也拿到锁locka,正在等待锁lockb被释放,这时两个线程都处于临时阻塞状态,都在等待对方释放锁。但是两边都不释放自己的锁。所以程序处于死锁状态。

死锁是设计代码时,应当极力避免的。

 

 

 

                        

                                   ------- android培训java培训、期待与您交流! ----------

  • 大小: 34.3 KB
  • 大小: 4.9 KB
  • 大小: 5.1 KB
  • 大小: 3.3 KB
分享到:
评论

相关推荐

    黑马程序员_张孝祥_Java多线程与并发库 视频+代码+资料

    黑马程序员_张孝祥_Java多线程与并发库,视频+代码+资料

    黑马程序员_张孝祥_Java多线程与并发库

    黑马程序员_张孝祥_Java多线程与并发库,老师讲的非常仔细,老师很有耐心.欢迎大家下载学习.

    黑马程序员-java多线程技术01

    NULL 博文链接:https://huangminwen.iteye.com/blog/1157983

    黑马程序员–Java多线程讲解笔记

    当一个进程中线程有多个时,是多线程。  为什么要用多线程  1,让计算机"同时"做多件事情,节约时间。  2,后台运行程序,提高程序的运行效率.。  3,多线程可以让程序"同时"处理多个事情。  4,...

    传智播客.黑马程序员《Java 基础入门》课后习题答案

    1、 面向对象、跨平台性、健壮性、安全性、可移植性、多线程性、动态性等。 2、 JRE(Java Runtime Environment,Java 运行时环境),它相当于操作系统部分,提供了 Java 程序运 行时所需要的基本条件和许多 Java ...

    java拼图游戏源码.zip

    这是一个java写的拼图游戏,用了swing、多线程等知识,可以设置行数列、列数、还有使用多线程写的游戏动画,拼图的图块具有磁贴设计,代码封装性较强,容易移植,纯原创。

    java并发库高级应用源码--张孝祥

    java并发库thread使用,传统线程技术、定时器技术、线程互斥技术,同步通讯技术、多线程共享数据、并发库应用,线程锁技术,阻塞锁、阻塞队列,线程池等应用

    图解java多线程设计模式

    java.util.concurrent包、synchronized关键字、Swing框架、Java内存模型等内容也均有涉及,不仅能够了解Java多线程的相关知识,还可加深对Java语言的理解。 本书适合以下读者阅读 a.对多线程感兴趣的人 b.对Java...

    传智播客_Java培训_毕向东_Java基础[05-多线程]

    传智播客_Java培训_毕向东_Java基础[05-多线程]系黑马程序员_毕向东_Java基础视频教程

    图解java多线程设计模式2017年8月最新版

    264张图表 + 300段Java示例程序 = 轻松学习多线程编程 日本经典多线程入门书,原版长销11年! 本书适合以下读者阅读 a.对多线程感兴趣的人 b.对Java编程感兴趣的人 c.对设计模式感兴趣的人 d.对面向对象开发感兴趣的...

    《Java基础案例教程(第2版)》课后习题答案1

    第1章 Java开发入门一.填空题1. 面向对象,SUN 2. JavaSE,JavaEE,JavaME3.面向对象、跨平台性、支持多线程4. JDK5.bin

    黑马程序员 安卓学院 万元哥项目经理 分享220个代码实例

    |--利用FinalHttp实现多线程断点续传 |--加密之MD5 |--动画Animation详解 |--动画之view左右抖动 |--动画之移动动画 |--动画之组合动画 |--动画之缩放动画ScaleAnimation |--反序列化对象 |--发送短信 读天气 调音量...

    拼图游戏 (源码+所有文件)

    萌新做的一个简单的Java拼图游戏 启动类:pers.sept.jigsaw1.swing下的...多线程。 下拉列表选择数字可以切换关卡图片,最后的“+”,可以添自己的图片到关卡中。 设有背景音乐 有一键通过按钮 等等,块下载去看看吧。

    图解java多线程设计模式 2017年8月最新版

    这本书的pdf文件有162M,是最新版高清的pdf,网上原书售价60多元,这里提供的附件是百度云的链接地址。

    JAVA核心知识点整理.pdf

    给大家分享一篇我在学习java过程中...包含常见的面试题:JVM、Java集合、多线程并发、java基础、SSM框架原理、微服务、Netty和RPC、网络、日志、算法、数据结构、加密、分布式算法、机器学习、大数据等知识点,都是干货

    学成在线-分布式任务视频处理

    2.适用于黑马程序员Java企业级实战开发《学成在线》微服务项目,基于SpringCloud、SpringCloudAlibaba技术栈开发。 3.采用xxl-job技术。 4.步骤概要: 4.1 作业分片方案 4.2 保证任务不重复执行 4.3 业务流程 5....

    java7源码-Java-concurrent:Java并发编程

    黑马程序员——Java异步课程源码 plugin Lombok logback.xml 说明 课堂代码主要在 case_java8 子模块内,按章节划分, io.github.hank.java.concurrent.n2 - 同步与异步 io.github.hank.java.concurrent.n3 - Java...

    黑马乐优商城项目后台管理系统.zip

    它由Sun Microsystems(现在是Oracle Corporation)的James Gosling等人在1995年推出,被设计为一种简单、健壮、可移植、多线程、动态的语言。Java的主要特点和优势包括以下几个方面: 跨平台性(Write Once, Run ...

    Java基础最全笔记文档

    Java基础笔记分为 Java基础篇 和 Java加强篇 Java基础篇包括: 1. Java环境搭建、Java快速入门、IDEA开发工具 ...11. 多线程 12. 网络编程 13. 单元测试、反射、注解、动态代理 14. XML、解析、工厂模式和装饰模式

    黑马JVM学习笔记二

    title: 黑马JVM学习笔记二 date: 2020-01-13 1:00:00 ...线程是私有的,多线程之间分别有各自的程序计数器记录对应线程的执行位置 程序计数器是Java虚拟机规范中唯一一个不会存在内存溢出的区(堆和栈等会出现内存溢

Global site tag (gtag.js) - Google Analytics