多线程

多线程:

 

1.进程与线程的区别:

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

Eg:任务管理器中.正在运行的程序.(应用客户端等)

2.多线程的意义.提高CPU的使用效率

3.多线程中:线程是同时进行的吗:

不是,是切换进行.CPU的时间片在进程之间高效切换.

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

多线程的意义:一个进程中开启多个任务,任务互相抢占CPU的执行权

.线程有随机性. 线程的优先级高不一定抢到线程.

 

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

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

 

JVM是多线程程序吗?

是多线程.由于Java虚拟机自带一个垃圾回收器,保证程序不会轻易的造成溢出

至少开启两个子线程:1.main()主线程 2.垃圾回收线程

 

 

实现多线程?

先创建一个进程.

创建进程需要调用系统资源进行创建.但是java语言不能直接调用.

Java使用C/C++封装好的东西.

并发和并行:

并发:同一时间点

并行:同一时间段.

多线程实现方式:

1.     自定义一个类:MyThread继承自Thread类

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

3.     在主线程成,创建该类的实例对象,启动线程.

Eg

1.     自定义一个类:MyThread继承自Thread类

publicclass MyThread extends Thread {

 

 

/*

 * 重写Thread类中的run()方法

 * */

@Override

public void run() {

//               System.out.println("helloworld");

          //耗时的操作,线程睡眠,线程等待,循环语句

          for(int x = 0 ; x <100 ; x ++){

                   System.out.println(x);

          }

}

}

 

测试类:

public class MyThreadDemo {

public static void main(String[] args) {

    //创建实例对象

//  MyThread mt = new MyThread();

    //启动线程使用的start()方法.其实JVm调用run方法.start调用

    MyThread mt1 = new MyThread() ;

    MyThread mt2 = new MyThread() ;

    mt1.start();

    mt2.start();

   

}

}

 

获取线程名称:

Public final String getName()返回线程名称

设置线程名称:

Public final voidsetName(String name)改变线程名称:

 

public class MyThread extends Thread{

    public MyThread(){  

    }

    public MyThread(String name){

       super(name) ;

    }  

    @Override

    public void run(){

       for(int x=100;x<100;x++){

           System.out.println(getName()+" "+x);

       }

    }

}

测试类:

public class ThreadDemo1 {

public static void main(String[] args) {

    MyThread my1 = new MyThread() ;

    MyThread my2 = new MyThread() ;

    // public final void setName(String name)改变线程名称,使之与参数 name 相同。

    my1.setName("蛮王") ;

    my2.setName("艾希") ;

    //main是主线程

//  System.out.println(Thread.currentThread().getName());

    my1.start() ;

    my2.start() ;

}

}

 

Join方法:

public class JoinThread extends Thread{

    @Override

    public void run(){

       for(int x=0;x<100;x++){

           System.out.println(getName()+":"+x);

       }

    }

   

}

 

public class JoinDemo {

public static void main(String[] args) {

    JoinThread s1 = new JoinThread();

    JoinThread s2 = new JoinThread();

    JoinThread s3=new JoinThread();

    s1.setName("UZI");

    s2.setName("Faker");

    s3.setName("Margin");

    s1.start();

    try {

       s1.join() ;

    } catch (InterruptedException e) {

       e.printStackTrace();

    }

    s2.start();

    s3.start();

}

}

 

先打印s1的再执行线程s2.s3.

 

设置线程优先级:

(1-10):默认为5 线程优先级越高也不是一定能抢到CPU线程有随机性.

线程.setPriority(优先级);

Yield():暂停当前执行的线程对象,执行其他的线程.

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

 

Public final void setDaemon(boolean  on) on指定为true,就是守护线程.

 

将线程设置为守护线程

该方法必须在启动线程前调用。,对于主线程的数据如果直接输出完毕,对于两个守护线程来说不会立即消失.(慢慢死亡)

 

public class ThreadDemaonDemo {

public static void main(String[] args) {

    ThreadDemaon td1 = new ThreadDemaon();

    ThreadDemaontd2 = new ThreadDemaon();

    td1.setName("JS") ;

    td2.setName("JJ") ;

    td1.setDaemon(true);

    td2.setDaemon(true);

    td1.start();

    td2.start();

    //设置主线程

    Thread.currentThread().setName("");

    for(int x = 0 ; x <5 ;x++){

       System.out.println(Thread.currentThread().getName()+":"+x);

    }

}

}

 

线程睡眠:

public static void sleep(long millis):

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

public class ThreadSleep extends Thread{

    @Override

    public void run(){

       for(int x = 0 ; x <100 ; x ++){

           System.out.println(getName()+":"+x+",日期:"+new Date());

           try {

              Thread.sleep(1000);

           } catch (InterruptedException e) {

              // TODO Auto-generatedcatch block

              e.printStackTrace();

           }

    }

}

}

 

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

Public void interrupt():中断线程.一种状态

 

Runnable接口实现多线程

public class MyRunnable implements Runnable {

    @Override

    public void run(){

       for(int x=0;x<100;x++){

           System.out.println(Thread.currentThread().getName()+":"+x);

       }

    }  

}

public class ThreadDemo3 {

public static void main(String[] args) {

    MyRunnable MR=new MyRunnable();

//  Thread t1 = new Thread();

//  t1.setName("线程1");//一种方法

    Thread s1 = new Thread(MR,"UZI");

    Thread s2 = new Thread(MR,"Faker");

    //第二种方法   经常采用

    s1.start();

    s2.start();

    }

}

 

多线程两种实现方式比较:

一:

1.     自定义一类MyThread继承自Thread类

2.     重写Thread类中的run()方法

3.     主线程创建线程实例

4.     启动线程

注意:启动线程使用start(),调用run()方法相当于调用普通方法.start()的调用实质是通过JVM调用底层run()方法

一个线程不能启动多次,否则出现非法线程状态异常

二:

1.     定义一个MyRunnable,,实习Runnable接口

2.     实现run方法

3.     主线程创建Myrunnble对象

4.     创建Thread类对象,将MyRunnable对象作为参数传递

5.     启动线程

单继承具有局限性:第二种方式更更符合设计原则:数据分类原则.

 

MyRunnable对象作为子线程的共有对象,java中多线程实习方式接口,方式大于继承

 

 

模拟电影院卖票场景,每一个窗口卖票应该延迟操作

在run()方法中加入让线程睡眠

当加入延时操作:可能出现1,0,-1  由于延迟操作和线程的随机性导致的.

 

解决多线程的安全问题(判断一个多线程是否有安全问题)

1.     是否处在一个多线程环境

2.     是否共享数据

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

 

public class SellTicket implements Runnable {

     private  static int ticket=100;

    @Override

    public void run() {

       while(true){

           if(ticket>0){

              try {

                  Thread.sleep(100);

              } catch (InterruptedException e) {

                  e.printStackTrace();

              }

              System.out.println(Thread.currentThread().getName()+"正在出售"+(ticket--)+"张票");

           }

       }

    }

}

public class SellTicketDemo {

  public static void main(String[] args) {

       SellTicket ST= new SellTicket();

       Thread s1=new Thread(ST,"窗口1");

       Thread s2=new Thread(ST,"窗口2");

       Thread s3=new Thread(ST,"窗口3");

       s1.start();

       s2.start();

       s3.start();

  }

}

在结果中出现了出售第0票.票的顺序不对.

 

第二种: 

@Override

     public void run() {

       while (true) {

           try {

              Thread.sleep(100);

           }catch (InterruptedException e) {

              e.printStackTrace();

           }

           if (ticket > 0) {

              System.out.println(Thread.currentThread().getName()+ "正在出售第"

                     +(ticket--) + "张票");

           }

}

 

结果:出现了0票和票的顺序乱的还有重票

 

解决问题:

1.  多线程环境和共享数据改变不了,同步机制可以改进

条件:将多条语句对共享数据的操作进行更改

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

3.  Java的同步机制

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

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

}

 

public class SellTicketT  implements Runnable{

    private Demo b=new Demo();

    private static int ticket=100;

    @Override

    public void run() {

    while(true){

       synchronized(b){

           if(ticket>0){

           try {

              Thread.sleep(100);

           } catch (InterruptedException e) {

              e.printStackTrace();

           }

           System.out.println(Thread.currentThread().getName()+":"+(ticket--));

           }

       }

    }  

    }

}

class Demo{  

}

 

锁的对象 b是在开始通过  类Demo 创建. 

Synchronize 加锁,以此保证线程安全.

本身锁的对象是Object类型:任意的Java类

可以当做一个门:加锁的时候将门关上,当代码执行完成,门打开,其他人可以进

 

线程安全的类?

Vector    StringBuffer    Hashtable        

Vector<String> v = new Vector<String>() ;

StringBuffer sb = newStringBuffer("StringHello") ;

Hashtable<String, String> hm = newHashtable<String,String>() ;//Map的子实现类

 

还有安全的集合列表.

 

同步锁对象:

1.     可以是Object类型以及任意的Java类型

2.     一个方法进来后是同步代码块,同步代码块可以演变成一个同步方法.

3.     一个静态的同步方法.所对象为当前类名的class 属性.

 

面试题:

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

 

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

同步代码块解决安全问题级出现同步锁对象.因此将方法定义到Object类

 

静态同步方法:同步锁对象为class

非静态的同步方法:同步锁对象为this

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值