java学习——多线程
本文内容来源于 历经5年锤练--史上最适合初学者入门的Java基础视频
线程:就是进程中一个负责程序执行的控制单元(执行路径)
每一个线程都有自己运行的内容。这个内容可以称为线程要执行的任务。
多线程好处:解决了多部分同时运行的问题。
多线程的弊端:线程太多回到效率的降低。
JVM启动时就启动了多个线程,至少有两个线程可以分析的出来。
1,执行main函数的线程,
该线程的任务代码都定义在main函数中。
2,负责垃圾回收的线程。
多线程状态图:
如何创建一个线程呢?
创建线程方式一:继承Thread类。
步骤:
1,定义一个类继承Thread类。
2,覆盖Thread类中的run方法。
3,直接创建Thread的子类对象创建线程。
4,调用start方法开启线程并调用线程的任务run方法执行。
- class Demo extends Thread{
- ......
- public void run(){
- ......
- }
- }
- class ThreadDemo2 {
- public static void main(String[] args) {
- Demo d1 = new Demo();
- d1.start();//开启线程,调用run方法。
- }
- class Demo extends Thread{
- private String name;
- Demo(String name){
- super(name);
- //this.name = name;
- }
- public void run(){
- for(int x=0; x<10; x++){
- System.out.println(name+"....x="+x+".....name="+Thread.currentThread().getName());
- }
- }
- }
- class ThreadDemo2 {
- public static void main(String[] args) {
- Demo d1 = new Demo("旺财");
- Demo d2 = new Demo("xiaoqiang");
- d1.start();//开启线程,调用run方法。
- d2.start();
- System.out.println("over...."+Thread.currentThread().getName());
- }
- }
线程创建方式二:实现Runnable接口(比较常用)
步骤:
1,定义类实现Runnable接口。
2,覆盖接口中的run方法,将线程的任务代码封装到run方法中。
3,通过Thread类创建线程对象,并将Runnable接口的子类对象作为Thread类的构造函数的参数进行传递。
4,调用线程对象的start方法开启线程。
实现Runnable接口的好处:
1,将线程的任务从线程的子类中分离出来,进行了单独的封装。
按照面向对象的思想将任务的封装成对象。
2,避免了java单继承的局限性。
- class Demo implements Runnable{
- public void run(){
- ...
- }
- }
- class ThreadDemo{
- public static void main(String[] args) {
- Demo d = new Demo();
- Thread t1 = new Thread(d);
- Thread t2 = new Thread(d);
- t1.start();
- t2.start();
- }
- }
小例子:卖票
线程安全问题产生的原因:
1,多个线程在操作共享的数据。
2,操作共享数据的线程代码有多条。
当一个线程在执行操作共享数据的多条代码过程中,其他线程参与了运算。
就会导致线程安全问题的产生。
解决思路;
就是将多条操作共享数据的线程代码封装起来,当有线程在执行这些代码的时候,
其他线程时不可以参与运算的,必须要当前线程把这些代码都执行完毕后,其他线程才可以参与运算。
在java中,用同步代码块就可以解决这个问题。
同步代码块的格式:
synchronized(对象)
{
需要被同步的代码 ;
}
同步的好处:解决了线程的安全问题。
同步的弊端:相对降低了效率,因为同步外的线程的都会判断同步锁。
同步的前提:同步中必须有多个线程并使用同一个锁。
- class Ticket implements Runnable{
- private int num = 100;
- Object obj = new Object();
- public void run(){
- while(true){
- synchronized(obj){ //锁是任意的,可以使用this,即 synchronized(this)
- if(num>0){
- try{Thread.sleep(10);}catch (InterruptedException e){} //睡一下便于发现是否有安全隐患
System.out.println(Thread.currentThread().getName()+".....sale...."+num--);- }
- }
- }
- }
- }
- class TicketDemo{
- 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();
- }
- }
小例子2:储户,两个,每个都到银行(同一个银行)存钱每次存100,,共存三次。
涉及:同步函数
- class Bank{
- private int sum;
- public synchronized void add(int num)//同步函数:同步的第二种表现形式,锁是this
- {
- sum = sum + num;
- try{Thread.sleep(10);}catch(InterruptedException e){}
- System.out.println("sum="+sum);
- }
- }
- class Cus implements Runnable{
- private Bank b = new Bank();
- public void run(){
- for(int x=0; x<3; x++){
- b.add(100);
- }
- }
- }
- class BankDemo {
- public static void main(String[] args) {
- Cus c = new Cus();
- Thread t1 = new Thread(c);
- Thread t2 = new Thread(c);
- t1.start();
- t2.start();
- }
- }
同步函数锁:
同步函数的使用的锁是this;
同步函数和同步代码块的区别:同步函数的锁是固定的this, 同步代码块的锁是任意的对象。
建议使用同步代码块。
静态的同步函数使用的锁是 该函数所属字节码文件对象
可以用 getClass方法获取,也可以用当前 类名.class 表示。
- class Ticket implements Runnable{
- private static int num = 100;
- // Object obj = new Object();
- boolean flag = true;
- public void run(){
- // System.out.println("this:"+this.getClass());
- if(flag)
- while(true){
- synchronized(Ticket.class)//(this.getClass())
- { if(num>0){
- try{Thread.sleep(10);}catch (InterruptedException e){}
- System.out.println(Thread.currentThread().getName()+".....obj...."+num--);
- }
- }
- }
- else
- while(true)
- this.show();
- }
- public static synchronized void show(){
- if(num>0){
- try{Thread.sleep(10);}catch (InterruptedException e){}
- System.out.println(Thread.currentThread().getName()+".....function...."+num--);
- }
- }
- }
- class StaticSynFunctionLockDemo {
- public static void main(String[] args) {
- Ticket t = new Ticket();
- // Class clazz = t.getClass();
- // Class clazz = Ticket.class;
- // System.out.println("t:"+t.getClass());
- Thread t1 = new Thread(t);
- Thread t2 = new Thread(t);
- t1.start();
- try{Thread.sleep(10);}catch(InterruptedException e){}
- t.flag = false;
- t2.start();
- }
- }
复习:单例设计模式
设计模式:对问题行之有效的解决方式。其实它是一种思想。
1,单例设计模式。
解决的问题:就是可以保证一个类在内存中的对象唯一性。
必须对于多个程序使用同一个配置信息对象时,就需要保证该对象的唯一性。
如何保证对象唯一性呢?
1,不允许其他程序用new创建该类对象。
2,在该类创建一个本类实例。
3,对外提供一个方法让其他程序可以获取该对象。
步骤:
1,私有化该类构造函数。
2,通过new在本类中创建一个本类对象。
3,定义一个公有的方法,将创建的对象返回。
//饿汉式(开发常用)
- class Single//类一加载,对象就已经存在了。
- {
- private static Single s = new Single();
- private Single(){}
- public static Single getInstance()
- {return s;}
- }
//懒汉式(面试常用)有安全问题
- class Single2//类加载进来,没有对象,只有调用了getInstance方法时,才会创建对象。延迟加载形式。
- { private static Single2 s = null;
- private Single2(){}
- public static Single2 getInstance(){
if(s==null)- s = new Single2();
- return s;}
- }
多线程下的单例模式:
饿汉式没有安全问题,对懒汉式进行修改
加入同步为了解决多线程安全问题。
加入双重判断是为了解决效率问题。
- class Single{
- private static Single s = null;
- private Single(){}
- public static Single getInstance(){
- if(s==null){//当s不为null时,则不进行锁的判断,直接返回s
- synchronized(Single.class){
- if(s==null)
- // -->0 -->1
- s = new Single();
- }
- }
- return s;
- }
- }
死锁: 常见情景之一:同步的嵌套。
- class Ticket implements Runnable{
- private int num = 100;
- Object obj = new Object();
- boolean flag = true;
- public void run(){
- if(flag)
- while(true){
- synchronized(obj){
- show();
- }
- }
- else
- while(true)
- this.show();
- }
- public synchronized void show(){
- synchronized(obj){
- if(num>0){
- try{Thread.sleep(10);}catch (InterruptedException e){} System.out.println(Thread.currentThread().getName()+".....sale...."+num--);
- }
- }
- }
- }
- class DeadLockDemo {
- public static void main(String[] args) {
- Ticket t = new Ticket();
- // System.out.println("t:"+t);
- Thread t1 = new Thread(t);
- Thread t2 = new Thread(t);
- t1.start();
- try{Thread.sleep(10);}catch(InterruptedException e){}
- t.flag = false;
- t2.start();
- }
- }
死锁同步嵌套Demo
- 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{
- public static final Object locka = new Object();
- public static final Object lockb = new Object();
- }
- class DeadLockTest {
- public static void main(String[] args) {
- Test a = new Test(true);
- Test b = new Test(false);
- Thread t1 = new Thread(a);
- Thread t2 = new Thread(b);
- t1.start();
- t2.start();
- }
- }
线程间通讯:
多个线程在处理同一资源,但是任务却不同。
- //资源
- class Resource{
- String name;
- String sex;
- }
- //输入
- class Input implements Runnable{
- Resource r ;
- // Object obj = new Object();
- Input(Resource r){
- this.r = r;
- }
- public void run(){
- int x = 0;
- while(true){
- synchronized(r){
- if(x==0){
- r.name = "mike";
- r.sex = "nan";
- }
- else{
- r.name = "丽丽";
- r.sex = "女女女女女女";
- }
- }
- x = (x+1)%2;
- }
- }
- }
- //输出
- class Output implements Runnable{
- Resource r;
- // Object obj = new Object();
- Output(Resource r){
- this.r = r;
- }
- public void run(){
- while(true){
- synchronized(r){
- System.out.println(r.name+"....."+r.sex);
- }
- }
- }
- }
- class ResourceDemo{
- public static void main(String[] args) {
- //创建资源。
- Resource r = new Resource();
- //创建任务。
- Input in = new Input(r);
- Output out = new Output(r);
- //创建线程,执行路径。
- Thread t1 = new Thread(in);
- Thread t2 = new Thread(out);
- //开启线程
- t1.start();
- t2.start();
- }
- }
线程间通讯:等待唤醒机制
等待/唤醒机制。
涉及的方法:
1,wait(): 让线程处于冻结状态,被wait的线程会被存储到线程池中。
2,notify():唤醒线程池中一个线程(任意).
3,notifyAll():唤醒线程池中的所有线程。
这些方法都必须定义在同步中。
因为这些方法是用于操作线程状态的方法。
必须要明确到底操作的是哪个锁上的线程。
为什么操作线程的方法wait notify notifyAll定义在了Object类中?
因为这些方法是监视器的方法。监视器其实就是锁。
锁可以是任意的对象,任意的对象调用的方式一定定义在Object类中。
- //资源
- class Resource
- {
- String name;
- String sex;
- boolean flag = false;
- }
- //输入
- class Input implements Runnable
- {
- Resource r ;
- // Object obj = new Object();
- Input(Resource r)
- {
- this.r = r;
- }
- public void run()
- {
- int x = 0;
- while(true)
- {
- synchronized(r)
- {
- if(r.flag)
- try{r.wait();}catch(InterruptedException e){}
- if(x==0)
- {
- r.name = "mike";
- r.sex = "nan";
- }
- else
- {
- r.name = "丽丽";
- r.sex = "女女女女女女";
- }
- r.flag = true;
- r.notify();
- }
- x = (x+1)%2;
- }
- }
- }
- //输出
- class Output implements Runnable
- {
- Resource r;
- // Object obj = new Object();
- Output(Resource r)
- {
- this.r = r;
- }
- public void run()
- {
- while(true)
- {
- synchronized(r)
- {
- if(!r.flag)
- try{r.wait();}catch(InterruptedException e){}
- System.out.println(r.name+"....."+r.sex);
- r.flag = false;
- r.notify();
- }
- }
- }
- }
- class ResourceDemo2
- {
- public static void main(String[] args)
- {
- //创建资源。
- Resource r = new Resource();
- //创建任务。
- Input in = new Input(r);
- Output out = new Output(r);
- //创建线程,执行路径。
- Thread t1 = new Thread(in);
- Thread t2 = new Thread(out);
- //开启线程
- t1.start();
- t2.start();
- }
- }
代码优化:
- class Resource
- {
- private String name;
- private String sex;
- private boolean flag = false;
- public synchronized void set(String name,String sex)
- {
- if(flag)
- try{this.wait();}catch(InterruptedException e){}
- this.name = name;
- this.sex = sex;
- flag = true;
- this.notify();
- }
- public synchronized void out()
- {
- if(!flag)
- try{this.wait();}catch(InterruptedException e){}
- System.out.println(name+"...+...."+sex);
- flag = false;
- notify();
- }
- }
- //输入
- class Input implements Runnable
- {
- Resource r ;
- // Object obj = new Object();
- Input(Resource r)
- {
- this.r = r;
- }
- public void run()
- {
- int x = 0;
- while(true)
- {
- if(x==0)
- {
- r.set("mike","nan");
- }
- else
- {
- r.set("丽丽","女女女女女女");
- }
- x = (x+1)%2;
- }
- }
- }
- //输出
- class Output implements Runnable
- {
- Resource r;
- // Object obj = new Object();
- Output(Resource r)
- {
- this.r = r;
- }
- public void run()
- {
- while(true)
- {
- r.out();
- }
- }
- }
- class ResourceDemo3
- {
- public static void main(String[] args)
- {
- //创建资源。
- Resource r = new Resource();
- //创建任务。
- Input in = new Input(r);
- Output out = new Output(r);
- //创建线程,执行路径。
- Thread t1 = new Thread(in);
- Thread t2 = new Thread(out);
- //开启线程
- t1.start();
- t2.start();
- }
- }
未完......
java学习——多线程的更多相关文章
- Java学习多线程第一天
内容介绍 Thread 线程创建 线程池 线程状态图 1 多线程 1.1 多线程介绍 学习多线程之前,我们先要了解几个关于多线程有关的概念. 进程:进程指正在运行的程序.确切的来说,当一个程序 ...
- Java学习---多线程的学习
基础知识 每个正在系统上运行的程序都是一个进程(process).每个进程包含一到多个线程(thread).进程也可能是整个程序或者是部分程序的动态执行. 线程是一组指令的集合,或者是程序的特殊段,它 ...
- java学习多线程之生产者消费者
在java多线程当中还有一种关系需要我们来重点掌握,那就是生产者和消费者的关系.那么什么是生产者,什么是消费者呢?我们可以举个例子来说,有张三.李四负责生产烤鸭,王五.马六负责吃烤鸭,那么前者生产完烤 ...
- java学习多线程之卖票示例
这一节我们来说一个示例就是卖票示例: 需求: 我们现在有100张票,然后分四个窗口来卖,直到卖完为止. 思路: 1.先定一个一个票类,描述票的属性,还有打印卖出的票,并且实现Runnable中的run ...
- java学习多线程之创建多线程一
现在我们有这么一个需求,就是在主线程在运行的同时,我们想做其他的任务,这个时候我们就用到了多线程.那么如何创建多线程,我们知道在系统当中qq的多线程创建是由操作系统来完成的,那么如果我们想在java当 ...
- [Java学习]多线程
关于多进程与多线程 使用多进程的目的:提高CPU利用率. 使用多线程的目的:提高应用程序?利用率. 多线程与多进程区别:进程间内存独立:同一个进程的线程间共享"堆内存和方法区内存" ...
- Java学习多线程第二天
内容介绍 线程安全 线程同步 死锁 Lock锁 等待唤醒机制 1 多线程 1.1 线程安全 如果有多个线程在同时运行,而这些线程可能会同时运行这段代码.程序每次运行结果和单线程运行的结果 ...
- Java学习|多线程学习笔记
什么是线程? 可以理解为进程中独立运行的字任务. 使用多线程: 1.继承Thread类:从源码可以看到,Thread累实现了Runnable接口. 如果多次调用st ...
- java学习多线程之死锁
形成死锁的前提是同步代码块嵌套. 什么是死锁?当一个线程拿到锁以后在这个锁内部的代码需要访问另一段的代码的时候另外一个程序的锁被另外一个线程拿到,这样的话,就造成了两个锁互不想让程序没法往下执行的这种 ...
随机推荐
- Android 判断当前网络连接类型
实际应用开发时,如果存在需要用户获取大量数据的情况,最好是先判断下网络类型,提示用户当前的网络类型,是否需要连接Wifi,etc.(手机流量太贵啦,当然土豪是无视这玩意的, (/ □ \)). 定义网 ...
- Acunetix Web Vulnerability Scanner Python辅助脚本
WvsScannerQueue.pyVersion: Python 2.7.* Acunetix Web Vulnerability Scanner 辅助Python脚本的第一个版本.功能:扫描URL ...
- SPSS时间序列分析
时间序列分析必须建立在预处理的基础上…… 今天看了一条新闻体会到了网络日志的重要性…… 指数平滑法(Exponential Smoothing,ES)是布朗(Robert G..Brown)所提出,布 ...
- osvdb
http://www.91ri.org/3117.html http://linux.cn/article-5332-1-rss.html http://www.freebuf.com/article ...
- UMHexagonS搜索过程
通过相邻块的预测得到mvp后,会以mvp为基础搜索最佳的匹配块,UMHexagonS就是h.264中用的一种搜索算法. UMHexagonS是一种整像素搜索算法,也就是搜索过程中,参考图像一直都是原来 ...
- Windows NT 驱动程序开发人员提示 -- 应注意避免的事项
下面是开发人员在使用 Windows NT 设备驱动程序时应当避免的事项列表: 1. 一定不要在没有标注 I/O 请求数据包 (IRP) 挂起 (IoMarkIrpPending) 的情况下通过调度 ...
- 设计模式(六):Singleton 单件模式 -- 创建型模式
1.定义 当需要控制一个类的实例数量且调用者可以从一个公共的访问点访问时. 2.适用场景 1. 当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时. 2. 当这个唯一实例应该是通过子类化可扩 ...
- 前端问题——png图片在IE6下透明失效,解决办法
今天,一位同事问我问题,png 图片在IE6下透明背景失效. 解决办法,在网上查了很多,最后还是采用两种方案来解决这个问题 1.把这个网页的png格式图片变更为gif格式的图片.问题解决 2.就是让这 ...
- UVAlive4287 Proving Equivalences(scc)
题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=10294 [思路] 强连通分量. 求出bcc后,缩点形成DAG,设D ...
- [git] github 使用简单记录
前提 :1. 已有 github 账号.2. 已安装 git .3. 在 github 和 本地 git 客户端交互秘钥.(这步我记得需要做,有点久远,不确定.) 正文: 下面是一个简单的例子.先在 ...