zoukankan      html  css  js  c++  java
  • 多线程


    * 主线程:执行主(main)方法的线程,叫做主线程
    * 程序执行的入口是main方法
    * 程序从main方法开始执行,从上到下依次执行,这个程序就是一个单线程的程序
    *
    * java程序进入到内存中执行,就是一个进程
    * JVM(java虚拟机),会先执行程序的入口main方法
    * JVM会找操作系统开辟一条java程序通向cpu的路径
    * cpu通过这个路径就可以执行main方法
    * 这个路径有一个名字,叫做主线程(main线程)



    * 实现多线程的第一种方式:将类声明为 Thread 的子类
    *
    * 实现步骤:
    * 1.创建一个Thread类的子类
    * 2.重写Thread类中的run方法,设置线程任务(开启线程要干什么事情)
    * 3.创建Thread类的子类对象
    * 4.调用Thread类中的方法start方法,开启一个新的线程执行run方法

    public class Demo01Thread {
    public static void main(String[] args) {
    //3.创建Thread类的子类对象
    MyThread mt = new MyThread();
    //4.调用Thread类中的方法start方法,开启一个新的线程执行run方法
    mt.start();
    
    new MyThread().start();
    
    //mt.run(); //单线程程序
    for(int i=0; i<=20; i++){
    System.out.println("main:"+i);
    }
    }
    }
    package cn.itcast.demo02.Thread;
    /*
    * 1.创建一个Thread类的子类
    */
    public class MyThread extends Thread{
    //2.重写Thread类中的run方法,设置线程任务(开启线程要干什么事情)
    @Override
    public void run() {
    for(int i=0; i<=20; i++){
    System.out.println("run:"+i);
    //System.out.println(0/0);
    }
    }
    }



    * 设置线程的名称
    * 1.使用Thread类中的方法setName
    * void setName(String name) 改变线程名称,使之与参数 name 相同。
    * 2.创建带参数构造方法,参数传递线程的名称;方法中调用父类的带参数构造方法,把名称传递过父类,让父类帮子类起名字
    * Thread(String name) 分配新的 Thread 对象。

    * 获取线程的名称:
    * 1.可以通过Thread类中的方法getName获取
    * String getName() 返回该线程的名称。
    * 2.通过Thread类中的方法,先获取当前正在执行的线程,在通过线程中的方法getName获取线程名称
    * static Thread currentThread() 返回对当前正在执行的线程对象的引用。

    * start方法:
    * 使该线程开始执行;Java 虚拟机调用该线程的 run 方法。
    * 结果是两个线程并发地运行;当前线程(执行main方法的线程,主线程)和另一个线程(执行其 run 方法的线程,Thread-0,...)。
    * 多次启动一个线程是非法的。特别是当线程已经结束执行后,不能再重新启动。



    * 创建多线程的第二种方式:实现Runnable接口
    *
    * Thread类中的构造方法:传递的是Runnable接口的实现类对象
    * Thread(Runnable target) 分配新的 Thread 对象。
    *
    * 实现步骤:
    * 1.定义Runnable接口的实现类
    * 2.重写Runnable接口中的run方法,设置线程任务
    * 3.创建Runnable接口的实现类对象
    * 4.创建Thread类对象,构造方法中传递Runnable接口的实现类对象
    * 5.调用Thread类中的方法start,开启新线程,执行run方法
    *
    * 实现Runnable接口方式创建多线程的好处:
    * 1.避免了单继承的局限性.实现了接口还可以继承其它的类
    * 2.把设置线程任务和开启线程进行了解耦,增强程序的扩展性
    * 实现Runnable接口,重写run方法:目的就是设置线程任务
    * 把线程的运行交个Thread类

    public class Demo01Thread {
    public static void main(String[] args) {
    //3.创建Runnable接口的实现类对象
    RunnableImpl run = new RunnableImpl();
    //4.创建Thread类对象,构造方法中传递Runnable接口的实现类对象
    //Thread t = new Thread(run);
    Thread t = new Thread(new RunnableImpl2());
    //5.调用Thread类中的方法start,开启新线程,执行run方法
    t.start();
    
    for (int i = 1; i <= 20; i++) {
    System.out.println(Thread.currentThread().getName()+"-->"+i);
    }
    }
    }
    package cn.itcast.demo05.Runnable;
    /*
    * 1.定义Runnable接口的实现类
    */
    public class RunnableImpl implements Runnable{
    //2.重写Runnable接口中的run方法,设置线程任务
    @Override
    public void run() {
    for (int i = 1; i <= 20; i++) {
    System.out.println(Thread.currentThread().getName()+"-->"+i);
    }
    }
    
    }
    package cn.itcast.demo05.Runnable;
    /*
    * 1.定义Runnable接口的实现类
    */
    public class RunnableImpl2 implements Runnable{
    //2.重写Runnable接口中的run方法,设置线程任务
    @Override
    public void run() {
    for (int i = 0; i < 100; i++) {
    System.out.println("HelloWorld"+i);
    }
    }
    
    }

    * 多线程的匿名内部类的创建方式:
    * 匿名:创建的对象没有名字
    * 内部类:写在其他类内部的类
    *
    * 格式:
    * new 父类/接口(){
    * 重写父类/接口中的方法;
    * };
    * 匿名内部类的作用:把定义子类,重写父类/接口的方法,创建子类对象合成一步完成
    * 匿名内部类的结果:就是一个子类对象
    *

    * new Thread(){
    //重写Thread类中的run方法
    @Override
    public void run() {
    for (int i = 0; i < 5; i++) {
    System.out.println(Thread.currentThread().getName()+"-->"+i);
    }
    }
    }


    以上代码就是创建线程Thread的子类对象,就相当于 new MyThread();

    public class Demo01Thread {
    public static void main(String[] args) {
    //父类:Thread
    new Thread(){
    //重写Thread类中的run方法
    @Override
    public void run() {
    for (int i = 0; i < 50; i++) {
    System.out.println(Thread.currentThread().getName()+"-->"+i);
    }
    }
    }.start();
    System.out.println("-------------------");
    //接口:Runnable
    //多态 接口 匿名实现类对象
    Runnable r = new Runnable(){
    @Override
    public void run() {
    for (int i = 0; i < 50; i++) {
    System.out.println(Thread.currentThread().getName()+"-->"+i);
    }
    }
    };
    System.out.println("-------------------");
    new Thread(r).start();
    
    new Thread(new Runnable(){
    @Override
    public void run() {
    for (int i = 0; i < 50; i++) {
    System.out.println(Thread.currentThread().getName()+"-->"+i);
    }
    }
    }).start();
    }
    }

    * Thread类中的方法sleep
    * static void sleep(long millis) 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)
    * 让程序睡觉,睡醒了继续执行

    public class Demo02Sleeep {
    public static void main(String[] args) {
    //秒表
    for (int i = 1; i <=60; i++) {
    System.out.println(i);
    //让程序睡眠1秒=1000毫秒
    try {
    Thread.sleep(1000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
    }
    }


    * 实现多线程卖票:
    * 创建3个线程,同时卖同一百张票

    public class Demo01PayTicket {
    public static void main(String[] args) {
    //创建Runnable接口的实现类对象
    RunnableImpl run = new RunnableImpl();
    //创建3个线程,同时卖同一百张票
    Thread t0 = new Thread(run);
    Thread t1 = new Thread(run);
    Thread t2 = new Thread(run);
    t0.start();
    t1.start();
    t2.start();
    }
    }
    
    package cn.itcast.demo07.Synchronized;
    /*
    * 卖票案例出现了线程安全问题:出现重复的票和不存在的票
    * 
    * 解决线程安全问题的第一种方式:使用同步代码块
    * 格式:
    * synchronized(锁对象){
    * 可能出现线程安全问题的代码(访问了共享数据的代码)
    * }
    * 注意:
    * 必须要保证多个线程使用的锁对象是同一个锁对象
    */
    public class RunnableImpl implements Runnable{
    //定义一个共享的票源
    private int ticket = 100;
    //创建一个同步代码块的锁对象,可以是任意的对象
    Object obj = new Object();
    
    @Override
    public void run() {
    while(true){
    //添加一个同步代码块
    synchronized (obj) {
    if(ticket>0){
    
    //为了提高出现问题的概率,增加一个睡眠
    try {
    Thread.sleep(10);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    
    //有票进行卖票操作
    System.out.println(Thread.currentThread().getName()+"-->正在卖第"+ticket--+"张票");
    }
    }
    }
    }
    
    }


    或者:

    package cn.itcast.demo08.SynchronizedMethod;
    /*
    * 卖票案例出现了线程安全问题:出现重复的票和不存在的票
    * 
    * 解决线程安全问题的第二种方式:使用同步方法
    * 就是一个方法,在方法上添加一个关键字synchronized修饰
    * 
    * 格式:
    * 修饰符 synchronized 返回值类型 方法名(参数列表){
    * 可能出现线程安全问题的代码(访问了共享数据的代码)
    * }
    * 
    */
    public class RunnableImpl implements Runnable{
    //定义一个共享的票源
    private static int ticket = 100;
    
    //卖票
    @Override
    public void run() {
    System.out.println("this:"+this);//RunnableImpl@67064
    //让每个线程卖票重复执行
    while(true){
    //payTicket();
    payTicketStatic();
    }
    }
    
    /*
    * 静态的同步方法
    * 静态的同步方法锁对象不能是this,this创建对象之后才会出现的
    * 静态优先于非静态加载到内存中
    * 静态方法的锁对象是本类的class属性(class文件对象,反射)
    * RunnableImpl.class
    */
    public static /*synchronized*/ void payTicketStatic() {
    synchronized (RunnableImpl.class) {
    //判断是否还有票卖
    if(ticket>0){
    
    //为了提高出现问题的概率,增加一个睡眠
    try {
    Thread.sleep(10);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    
    //有票进行卖票操作
    System.out.println(Thread.currentThread().getName()+"-->正在卖第"+ticket--+"张票");
    //ticket--;
    }
    }
    }
    
    /*
    * 定义一个同步方法
    * 选中要抽出方法的代码,使用快捷键alt+shift+M,把代码抽取到一个方法中
    * 添加synchronized修饰
    * 同步方法的的锁对象是现在类对象RunnableImpl(this)
    * this:当前的对象
    */
    public /*synchronized*/ void payTicket() {
    synchronized (this) {
    //判断是否还有票卖
    if(ticket>0){
    
    //为了提高出现问题的概率,增加一个睡眠
    try {
    Thread.sleep(10);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    
    //有票进行卖票操作
    System.out.println(Thread.currentThread().getName()+"-->正在卖第"+ticket--+"张票");
    //ticket--;
    }
    }
    }
    
    }

    或者:

    package cn.itcast.demo09.Lock;
    
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    /*
    * 卖票案例出现了线程安全问题:出现重复的票和不存在的票
    * 
    * 解决线程安全问题的第一种方式:Lock锁,JDK1.5之后出现的新特性
    * java.util.concurrent.locks.Lock接口
    * 接口中的方法:
    * void lock() 获取锁。 
    * void unlock() 释放锁。
    * Lock接口的实现类
    * java.util.concurrent.locks.ReentrantLock类 implements Lock接口
    * 
    * 使用步骤:
    * 1.在成员位置创建一个Lock接口的实现类对象ReentrantLock
    * 2.在可能会出现线程安全问题的代码前,调用Lock中方法lock获取锁对象
    * 3.在可能会出现线程安全问题的代码后,调用Lock中方法unlock释放锁对象
    */
    public class RunnableImpl implements Runnable{
    //定义一个共享的票源
    private int ticket = 100;
    
    //1.在成员位置创建一个Lock接口的实现类对象ReentrantLock
    Lock lock = new ReentrantLock();//多态
    
    //卖票
    @Override
    public void run() {
    //让每个线程卖票重复执行
    while(true){
    //2.在可能会出现线程安全问题的代码前,调用Lock中方法lock获取锁对象
    lock.lock();
    //判断是否还有票卖
    if(ticket>0){
    //为了提高出现问题的概率,增加一个睡眠
    try {
    Thread.sleep(10);
    //有票进行卖票操作
    System.out.println(Thread.currentThread().getName()+"-->正在卖第"+ticket--+"张票");
    } catch (InterruptedException e) {
    e.printStackTrace();
    }finally {
    //无论程序是否出现异常,都会执行,用于释放资源
    //3.在可能会出现线程安全问题的代码后,调用Lock中方法unlock释放锁对象
    lock.unlock();    
    }
    }
    }
    }
    
    /*//卖票
    @Override
    public void run() {
    //让每个线程卖票重复执行
    while(true){
    //synchronized (this) {
    //2.在可能会出现线程安全问题的代码前,调用Lock中方法lock获取锁对象
    lock.lock();
    //判断是否还有票卖
    if(ticket>0){
    
    //为了提高出现问题的概率,增加一个睡眠
    try {
    Thread.sleep(10);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    
    //有票进行卖票操作
    System.out.println(Thread.currentThread().getName()+"-->正在卖第"+ticket--+"张票");
    //ticket--;
    }
    //}
    //3.在可能会出现线程安全问题的代码后,调用Lock中方法unlock释放锁对象
    lock.unlock();    
    }
    }*/
    
    }
    人生就像一场路途,尝遍酸甜苦辣,方知人生苦甜.
  • 相关阅读:
    反弹shell
    php-fpm(绕过open_basedir,结合ssrf)
    LNMP和LAMP的搭建
    linux常用命令 awk命令
    git 工作区管理
    linux常用命令 grep命令
    linux常用命令 print格式输出
    linux常用命令 cut字符截取命令
    linux常用命令 wc统计命令
    linux常用命令 sort排序命令
  • 原文地址:https://www.cnblogs.com/zennon/p/8290016.html
Copyright © 2011-2022 走看看