精华内容
下载资源
问答
  • 你需要的是什么,直接评论留言。 获取更多资源加微信公众号“Java帮帮” ... (是公众号,不是微信好友哦) ...还有“Java帮帮”今日头条号,技术文章与...(1)多线程:一个应用程序有多条执行路径 进程:正在执行的

    你需要的是什么,直接评论留言。

    获取更多资源加微信公众号“Java帮帮” (是公众号,不是微信好友哦)

    还有“Java帮帮”今日头条号,技术文章与新闻,每日更新,欢迎阅读

    学习交流请加Java帮帮交流QQ群553841695

    分享是一种美德,分享更快乐!


    1:多线程(理解)

    (1)多线程:一个应用程序有多条执行路径

    进程:正在执行的应用程序

    线程:进程的执行单元,执行路径

    单线程:一个应用程序只有一条执行路径

    多线程:一个应用程序有多条执行路径

    多进程的意义?

    提高CPU的使用率

    多线程的意义?

    提高应用程序的使用率

    (2)Java程序的运行原理及JVM的启动是多线程的吗?

    A:Java命令去启动JVM,JVM会启动一个进程,该进程会启动一个主线程。

    B:JVM的启动是多线程的,因为它最低有两个线程启动了,主线程和垃圾回收线程。


    package cn.itcast_01;

    /*

     * 进程:

     * 正在运行的程序,是系统进行资源分配和调用的独立单位。

     * 每一个进程都有它自己的内存空间和系统资源。

     * 线程:

     * 是进程中的单个顺序控制流,是一条执行路径

     * 一个进程如果只有一条执行路径,则称为单线程程序。

     * 一个进程如果有多条执行路径,则称为多线程程序。

     *

     *  举例:

     *   扫雷程序,迅雷下载

     *  

     *  大家注意两个词汇的区别:并行和并发。

     * 前者是逻辑上同时发生,指在某一个时间内同时运行多个程序。

     * 后者是物理上同时发生,指在某一个时间点同时运行多个程序。

     *

     * Java程序的运行原理:

     *  由java命令启动JVM,JVM启动就相当于启动了一个进程。

     *  接着有该进程创建了一个主线程去调用main方法。

     * 

     * 思考题:

     *  jvm虚拟机的启动是单线程的还是多线程的?

     *  多线程的。

     *  原因是垃圾回收线程也要先启动,否则很容易会出现内存溢出。

     *  现在的垃圾回收线程加上前面的主线程,最低启动了两个线程,所以,jvm的启动其实是多线程的。

     */

    public class MyThreadDemo {

    public static void main(String[] args) {

    System.out.println("hello");

    new Object();

    new Object();

    new Object();

    new Object();

    //...

    System.out.println("world");

    }

    }


    (3)多线程的实现方案(自己补齐步骤及代码 掌握)

    A:继承Thread类


    package cn.itcast_02;(1)


    /*

     * 该类要重写run()方法,为什么呢?

     * 不是类中的所有代码都需要被线程执行的。

     * 而这个时候,为了区分哪些代码能够被线程执行,java提供了Thread类中的run()用来包含那些被线程执行的代码。

     */

    public class MyThread extends Thread {


    @Override

    public void run() {

    // 自己写代码

    // System.out.println("好好学习,天天向上");

    // 一般来说,被线程执行的代码肯定是比较耗时的。所以我们用循环改进

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

    System.out.println(x);

    }

    }


    }

    package cn.itcast_02;(2)


    /*

     * 需求:我们要实现多线程的程序。

     * 如何实现呢?

     *  由于线程是依赖进程而存在的,所以我们应该先创建一个进程出来。

     *  而进程是由系统创建的,所以我们应该去调用系统功能创建一个进程。

     *  Java是不能直接调用系统功能的,所以,我们没有办法直接实现多线程程序。

     *  但是呢?Java可以去调用C/C++写好的程序来实现多线程程序。

     *  由C/C++去调用系统功能创建进程,然后由Java去调用这样的东西,

     *  然后提供一些类供我们使用。我们就可以实现多线程程序了。

     * 那么Java提供的类是什么呢?

     *  Thread

     *  通过查看API,我们知道了有2中方式实现多线程程序。

     * 

     * 方式1:继承Thread类。

     * 步骤

     *  A:自定义类MyThread继承Thread类。

     *  B:MyThread类里面重写run()?

     *  为什么是run()方法呢?

     *  C:创建对象

     *  D:启动线程

     */

    public class MyThreadDemo {

    public static void main(String[] args) {

    // 创建线程对象

    // MyThread my = new MyThread();

    // // 启动线程

    // my.run();

    // my.run();

    // 调用run()方法为什么是单线程的呢?

    // 因为run()方法直接调用其实就相当于普通的方法调用,所以你看到的是单线程的效果

    // 要想看到多线程的效果,就必须说说另一个方法:start()

    // 面试题:run()和start()的区别?

    // run():仅仅是封装被线程执行的代码,直接调用是普通方法

    // start():首先启动了线程,然后再由jvm去调用该线程的run()方法。

    // MyThread my = new MyThread();

    // my.start();

    // // IllegalThreadStateException:非法的线程状态异常

    // // 为什么呢?因为这个相当于是my线程被调用了两次。而不是两个线程启动。

    // my.start();


    // 创建两个线程对象

    MyThread my1 = new MyThread();

    MyThread my2 = new MyThread();


    my1.start();

    my2.start();

    }

    }


    B:实现Runnable接口


    package cn.itcast_05;(1)


    public class MyRunnable implements Runnable {


    @Override

    public void run() {

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

    // 由于实现接口的方式就不能直接使用Thread类的方法了,但是可以间接的使用

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

    }

    }

    }

    package cn.itcast_05;(2)


    /*

     * 方式2:实现Runnable接口

     * 步骤:

     *  A:自定义类MyRunnable实现Runnable接口

     *  B:重写run()方法

     *  C:创建MyRunnable类的对象

     *  D:创建Thread类的对象,并把C步骤的对象作为构造参数传递

     */

    public class MyRunnableDemo {

    public static void main(String[] args) {

    // 创建MyRunnable类的对象

    MyRunnable my = new MyRunnable();


    // 创建Thread类的对象,并把C步骤的对象作为构造参数传递

    // Thread(Runnable target)

    // Thread t1 = new Thread(my);

    // Thread t2 = new Thread(my);

    // t1.setName("林青霞");

    // t2.setName("刘意");


    // Thread(Runnable target, String name)

    Thread t1 = new Thread(my, "林青霞");

    Thread t2 = new Thread(my, "刘意");


    t1.start();

    t2.start();

    }

    }

    (4)线程的名字获取与设置



    package cn.itcast_03;(1)   


    public class MyThread extends Thread {


    public MyThread() {

    }

    public MyThread(String name){

    super(name);

    }


    @Override

    public void run() {

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

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

    }

    }

    }


    package cn.itcast_03;(2)   


    /*

     * 如何获取线程对象的名称呢?

     * public final String getName():获取线程的名称。

     * 如何设置线程对象的名称呢?

     * public final void setName(String name):设置线程的名称

     * 

     * 针对不是Thread类的子类中如何获取线程对象名称呢?

     * public static Thread currentThread():返回当前正在执行的线程对象

     * Thread.currentThread().getName()

     */

    public class MyThreadDemo {

    public static void main(String[] args) {

    // 创建线程对象

    //无参构造+setXxx()

    // MyThread my1 = new MyThread();

    // MyThread my2 = new MyThread();

    // //调用方法设置名称

    // my1.setName("林青霞");

    // my2.setName("刘意");

    // my1.start();

    // my2.start();

    //带参构造方法给线程起名字

    // MyThread my1 = new MyThread("林青霞");

    // MyThread my2 = new MyThread("刘意");

    // my1.start();

    // my2.start();

    //我要获取main方法所在的线程对象的名称,该怎么办呢?

    //遇到这种情况,Thread类提供了一个很好玩的方法:

    //public static Thread currentThread():返回当前正在执行的线程对象

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

    }

    }


    /*

    名称为什么是:Thread-? 编号


    class Thread {

    private char name[];


    public Thread() {

            init(null, null, "Thread-" + nextThreadNum(), 0);

        }

        

        private void init(ThreadGroup g, Runnable target, String name,

                          long stackSize) {

            init(g, target, name, stackSize, null);

        }

        

         private void init(ThreadGroup g, Runnable target, String name,

                          long stackSize, AccessControlContext acc) {

            //大部分代码被省略了

            this.name = name.toCharArray();

        }

        

        public final void setName(String name) {

            this.name = name.toCharArray();

        }

        

        

        private static int threadInitNumber; //0,1,2

        private static synchronized int nextThreadNum() {

            return threadInitNumber++; //return 0,1

        }

        

        public final String getName() {

            return String.valueOf(name);

        }

    }


    class MyThread extends Thread {

    public MyThread() {

    super();

    }

    }


    */



    (5)线程的调度和优先级问题

    A:线程的调度

    a:分时调度

    b:抢占式调度 (Java采用的是该调度方式)


    B:获取和设置线程优先级

    a:默认是5

    b:范围是1-10


    package cn.itcast_04;(1)


    public class ThreadPriority extends Thread {

    @Override

    public void run() {

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

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

    }

    }

    }

    package cn.itcast_04;(2)


    /*

     * 我们的线程没有设置优先级,肯定有默认优先级。

     * 那么,默认优先级是多少呢?

     * 如何获取线程对象的优先级?

     *  public final int getPriority():返回线程对象的优先级

     * 如何设置线程对象的优先级呢?

     *  public final void setPriority(int newPriority):更改线程的优先级。 

     * 

     * 注意:

     *  线程默认优先级是5。

     *  线程优先级的范围是:1-10。

     *  线程优先级高仅仅表示线程获取的 CPU时间片的几率高,但是要在次数比较多,或者多次运行的时候才能看到比较好的效果。

     * 

     * IllegalArgumentException:非法参数异常。

     * 抛出的异常表明向方法传递了一个不合法或不正确的参数。 

     * 

     */

    public class ThreadPriorityDemo {

    public static void main(String[] args) {

    ThreadPriority tp1 = new ThreadPriority();

    ThreadPriority tp2 = new ThreadPriority();

    ThreadPriority tp3 = new ThreadPriority();


    tp1.setName("东方不败");

    tp2.setName("岳不群");

    tp3.setName("林平之");


    // 获取默认优先级

    // System.out.println(tp1.getPriority());

    // System.out.println(tp2.getPriority());

    // System.out.println(tp3.getPriority());


    // 设置线程优先级

    // tp1.setPriority(100000);

    //设置正确的线程优先级

    tp1.setPriority(10);

    tp2.setPriority(1);


    tp1.start();

    tp2.start();

    tp3.start();

    }

    }




    (6)线程的控制(常见方法)

    A:休眠线程


    package cn.itcast_04;(1)


    import java.util.Date;


    public class ThreadSleep extends Thread {

    @Override

    public void run() {

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

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

    // 睡眠

    // 困了,我稍微休息1秒钟

    try {

    Thread.sleep(1000);

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    }

    }

    }

    package cn.itcast_04;(2)


    /*

     * 线程休眠

     * public static void sleep(long millis)

     */

    public class ThreadSleepDemo {

    public static void main(String[] args) {

    ThreadSleep ts1 = new ThreadSleep();

    ThreadSleep ts2 = new ThreadSleep();

    ThreadSleep ts3 = new ThreadSleep();


    ts1.setName("林青霞");

    ts2.setName("林志玲");

    ts3.setName("林志颖");


    ts1.start();

    ts2.start();

    ts3.start();

    }

    }


    B:加入线程(等待该线程终止)


    package cn.itcast_04;(1)


    public class ThreadJoin extends Thread {

    @Override

    public void run() {

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

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

    }

    }

    }

    package cn.itcast_04;(2)


    /*

     * public final void join():等待该线程终止。 

     */

    public class ThreadJoinDemo {

    public static void main(String[] args) {

    ThreadJoin tj1 = new ThreadJoin();

    ThreadJoin tj2 = new ThreadJoin();

    ThreadJoin tj3 = new ThreadJoin();


    tj1.setName("李渊");

    tj2.setName("李世民");

    tj3.setName("李元霸");


    tj1.start();

    try {

    tj1.join();

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    tj2.start();

    tj3.start();

    }

    }


    C:礼让线程


    package cn.itcast_04;(1)


    public class ThreadYield extends Thread {

    @Override

    public void run() {

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

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

    Thread.yield();

    }

    }

    }

    package cn.itcast_04;(2)


    /*

     * public static void yield():暂停当前正在执行的线程对象,并执行其他线程。 

     * 让多个线程的执行更和谐,但是不能靠它保证一人一次。

     */

    public class ThreadYieldDemo {

    public static void main(String[] args) {

    ThreadYield ty1 = new ThreadYield();

    ThreadYield ty2 = new ThreadYield();


    ty1.setName("林青霞");

    ty2.setName("刘意");


    ty1.start();

    ty2.start();

    }

    }


    D:后台线程


    package cn.itcast_04;(1)


    public class ThreadDaemon extends Thread {

    @Override

    public void run() {

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

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

    }

    }

    }

    package cn.itcast_04;(2)


    /*

     * public final void setDaemon(boolean on):将该线程标记为守护线程或用户线程。

     * 当正在运行的线程都是守护线程时,Java 虚拟机退出。 该方法必须在启动线程前调用。 

     * 

     * 游戏:坦克大战。

     */

    public class ThreadDaemonDemo {

    public static void main(String[] args) {

    ThreadDaemon td1 = new ThreadDaemon();

    ThreadDaemon td2 = new ThreadDaemon();


    td1.setName("关羽");

    td2.setName("张飞");


    // 设置收获线程

    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);

    }

    }

    }


    E:终止线程(掌握)


    package cn.itcast_04;(1)


    import java.util.Date;


    public class ThreadStop extends Thread {

    @Override

    public void run() {

    System.out.println("开始执行:" + new Date());


    // 我要休息10秒钟,亲,不要打扰我哦

    try {

    Thread.sleep(10000);

    } catch (InterruptedException e) {

    // e.printStackTrace();

    System.out.println("线程被终止了");

    }


    System.out.println("结束执行:" + new Date());

    }

    }

    package cn.itcast_04;(2)


    /*

     * public final void stop():让线程停止,过时了,但是还可以使用。

     * public void interrupt():中断线程。 把线程的状态终止,并抛出一个InterruptedException。

     */

    public class ThreadStopDemo {

    public static void main(String[] args) {

    ThreadStop ts = new ThreadStop();

    ts.start();


    // 你超过三秒不醒过来,我就干死你

    try {

    Thread.sleep(3000);

    // ts.stop();

    ts.interrupt();

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    }

    }


    (7)线程的生命周期(参照 线程生命周期图解.bmp)

    A:新建

    B:就绪

    C:运行

    D:阻塞

    E:死亡

    (8)电影院卖票程序的实现

    A:继承Thread类


    package cn.itcast_06;(1)


    public class SellTicket extends Thread {


    // 定义100张票

    // private int tickets = 100;

    // 为了让多个线程对象共享这100张票,我们其实应该用静态修饰

    private static int tickets = 100;


    @Override

    public void run() {

    // 定义100张票

    // 每个线程进来都会走这里,这样的话,每个线程对象相当于买的是自己的那100张票,这不合理,所以应该定义到外面

    // int tickets = 100;


    // 是为了模拟一直有票

    while (true) {

    if (tickets > 0) {

    System.out.println(getName() + "正在出售第" + (tickets--) + "张票");

    }

    }

    }

    }

    package cn.itcast_06;(2)


    /*

     * 某电影院目前正在上映贺岁大片(红高粱,少林寺传奇藏经阁),共有100张票,而它有3个售票窗口售票,

     * 请设计一个程序模拟该电影院售票。

     * 继承Thread类来实现。

     */

    public class SellTicketDemo {

    public static void main(String[] args) {

    // 创建三个线程对象

    SellTicket st1 = new SellTicket();

    SellTicket st2 = new SellTicket();

    SellTicket st3 = new SellTicket();


    // 给线程对象起名字

    st1.setName("窗口1");

    st2.setName("窗口2");

    st3.setName("窗口3");


    // 启动线程

    st1.start();

    st2.start();

    st3.start();

    }

    }


    B:实现Runnable接口


    package cn.itcast_07;(1)


    public class SellTicket implements Runnable {

    // 定义100张票

    private int tickets = 100;


    @Override

    public void run() {

    while (true) {

    if (tickets > 0) {

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

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

    }

    }

    }

    }

    package cn.itcast_07;(2)


    /*

     * 实现Runnable接口的方式实现

     */

    public class SellTicketDemo {

    public static void main(String[] args) {

    // 创建资源对象

    SellTicket st = new SellTicket();


    // 创建三个线程对象

    Thread t1 = new Thread(st, "窗口1");

    Thread t2 = new Thread(st, "窗口2");

    Thread t3 = new Thread(st, "窗口3");


    // 启动线程

    t1.start();

    t2.start();

    t3.start();

    }

    }


    (9)电影院卖票程序出问题

    A:为了更符合真实的场景,加入了休眠100毫秒。

    B:卖票问题

    a:同票多次

    b:负数票


    package cn.itcast_08;(1)


    public class SellTicket implements Runnable {

    // 定义100张票

    private int tickets = 100;


    // @Override

    // public void run() {

    // while (true) {

    // // t1,t2,t3三个线程

    // // 这一次的tickets = 100;

    // if (tickets > 0) {

    // // 为了模拟更真实的场景,我们稍作休息

    // try {

    // Thread.sleep(100); // t1就稍作休息,t2就稍作休息

    // } catch (InterruptedException e) {

    // e.printStackTrace();

    // }

    //

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

    // + (tickets--) + "张票");

    // // 理想状态:

    // // 窗口1正在出售第100张票

    // // 窗口2正在出售第99张票

    // // 但是呢?

    // // CPU的每一次执行必须是一个原子性(最简单基本的)的操作。

    // // 先记录以前的值

    // // 接着把ticket--

    // // 然后输出以前的值(t2来了)

    // // ticket的值就变成了99

    // // 窗口1正在出售第100张票

    // // 窗口2正在出售第100张票

    //

    // }

    // }

    // }

    @Override

    public void run() {

    while (true) {

    // t1,t2,t3三个线程

    // 这一次的tickets = 1;

    if (tickets > 0) {

    // 为了模拟更真实的场景,我们稍作休息

    try {

    Thread.sleep(100); //t1进来了并休息,t2进来了并休息,t3进来了并休息,

    } catch (InterruptedException e) {

    e.printStackTrace();

    }


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

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

    //窗口1正在出售第1张票,tickets=0

    //窗口2正在出售第0张票,tickets=-1

    //窗口3正在出售第-1张票,tickets=-2

    }

    }

    }

    }

    package cn.itcast_08;(2)


    /*

     * 实现Runnable接口的方式实现

     * 

     * 通过加入延迟后,就产生了连个问题:

     * A:相同的票卖了多次

     *  CPU的一次操作必须是原子性的

     * B:出现了负数票

     *  随机性和延迟导致的

     */

    public class SellTicketDemo {

    public static void main(String[] args) {

    // 创建资源对象

    SellTicket st = new SellTicket();


    // 创建三个线程对象

    Thread t1 = new Thread(st, "窗口1");

    Thread t2 = new Thread(st, "窗口2");

    Thread t3 = new Thread(st, "窗口3");


    // 启动线程

    t1.start();

    t2.start();

    t3.start();

    }

    }


    (10)多线程安全问题的原因(也是我们以后判断一个程序是否有线程安全问题的依据)

    A:是否有多线程环境

    B:是否有共享数据

    C:是否有多条语句操作共享数据


    package cn.itcast_09;(1)


    public class SellTicket implements Runnable {

    // 定义100张票

    private int tickets = 100;

    //创建锁对象

    private Object obj = new Object();


    // @Override

    // public void run() {

    // while (true) {

    // synchronized(new Object()){

    // if (tickets > 0) {

    // try {

    // Thread.sleep(100); 

    // } catch (InterruptedException e) {

    // e.printStackTrace();

    // }

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

    // + (tickets--) + "张票");

    // }

    // }

    // }

    // }

    @Override

    public void run() {

    while (true) {

    synchronized (obj) {

    if (tickets > 0) {

    try {

    Thread.sleep(100);

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

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

    + "正在出售第" + (tickets--) + "张票");

    }

    }

    }

    }

    }

    package cn.itcast_09;(2)


    /*

     * 如何解决线程安全问题呢?

     * 

     * 要想解决问题,就要知道哪些原因会导致出问题:(而且这些原因也是以后我们判断一个程序是否会有线程安全问题的标准)

     * A:是否是多线程环境

     * B:是否有共享数据

     * C:是否有多条语句操作共享数据

     * 

     * 我们来回想一下我们的程序有没有上面的问题呢?

     * A:是否是多线程环境

     * B:是否有共享数据

     * C:是否有多条语句操作共享数据

     * 

     * 由此可见我们的程序出现问题是正常的,因为它满足出问题的条件。

     * 接下来才是我们要想想如何解决问题呢?

     * A和B的问题我们改变不了,我们只能想办法去把C改变一下。

     * 思想:

     *  把多条语句操作共享数据的代码给包成一个整体,让某个线程在执行的时候,别人不能来执行。

     * 问题是我们不知道怎么包啊?其实我也不知道,但是Java给我们提供了:同步机制。

     * 

     * 同步代码块:

     *  synchronized(对象){

     *  需要同步的代码;

     *  }

     * 

     *  A:对象是什么呢?

     *  我们可以随便创建一个对象试试。

     *  B:需要同步的代码是哪些呢?

     *  把多条语句操作共享数据的代码的部分给包起来

     * 

     *  注意:

     *  同步可以解决安全问题的根本原因就在那个对象上。该对象如同锁的功能。

     *  多个线程必须是同一把锁。

     */

    public class SellTicketDemo {

    public static void main(String[] args) {

    // 创建资源对象

    SellTicket st = new SellTicket();


    // 创建三个线程对象

    Thread t1 = new Thread(st, "窗口1");

    Thread t2 = new Thread(st, "窗口2");

    Thread t3 = new Thread(st, "窗口3");


    // 启动线程

    t1.start();

    t2.start();

    t3.start();

    }

    }


    (11)同步解决线程安全问题(1)

      A:同步的特点:

    前提:

    多个线程

    解决问题的时候要注意:

    多个线程使用的是同一个锁对象

      B:同步的好处 

    同步的出现解决了多线程的安全问题。

      C:同步的弊端

    当线程相当多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率。

    package cn.itcast_10;


    public class SellTicket implements Runnable {


    // 定义100张票

    private int tickets = 100;


    // 定义同一把锁

    private Object obj = new Object();


    @Override

    public void run() {

    while (true) {

    // t1,t2,t3都能走到这里

    // 假设t1抢到CPU的执行权,t1就要进来

    // 假设t2抢到CPU的执行权,t2就要进来,发现门是关着的,进不去。所以就等着。

    // 门(开,关)

    synchronized (obj) { // 发现这里的代码将来是会被锁上的,所以t1进来后,就锁了。(关)

    if (tickets > 0) {

    try {

    Thread.sleep(100); // t1就睡眠了

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

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

    + "正在出售第" + (tickets--) + "张票 ");

    //窗口1正在出售第100张票

    }

    } //t1就出来可,然后就开门。(开)

    }

    }

    }

    package cn.itcast_10;


    /*

     * 举例:

     *  火车上厕所。

     * 

     * 同步的特点:

     *  前提:

     *  多个线程

     * 解决问题的时候要注意:

     * 多个线程使用的是同一个锁对象

     * 同步的好处 

     * 同步的出现解决了多线程的安全问题。

     * 同步的弊端

     * 当线程相当多时,因为每个线程都会去判断同步上的锁,

     * 这是很耗费资源的,无形中会降低程序的运行效率。

     */

    public class SellTicketDemo {

    public static void main(String[] args) {

    // 创建资源对象

    SellTicket st = new SellTicket();


    // 创建三个线程对象

    Thread t1 = new Thread(st, "窗口1");

    Thread t2 = new Thread(st, "窗口2");

    Thread t3 = new Thread(st, "窗口3");


    // 启动线程

    t1.start();

    t2.start();

    t3.start();

    }

    }



    (11)同步解决线程安全问题(2)

    A:同步代码块

    synchronized(对象) {

    需要被同步的代码;

    }

    这里的锁对象可以是任意对象。

    B:同步方法

    把同步加在方法上。

    这里的锁对象是this

    C:静态同步方法

    把同步加在方法上。

    这里的锁对象是当前类的字节码文件对象(反射再讲字节码文件对象)


    package cn.itcast_11;(1)


    public class SellTicket implements Runnable {


    // 定义100张票

    private static int tickets = 100;


    // 定义同一把锁

    private Object obj = new Object();

    private Demo d = new Demo();


    private int x = 0;

    //同步代码块用obj做锁

    // @Override

    // public void run() {

    // while (true) {

    // synchronized (obj) {

    // if (tickets > 0) {

    // try {

    // Thread.sleep(100);

    // } catch (InterruptedException e) {

    // e.printStackTrace();

    // }

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

    // + "正在出售第" + (tickets--) + "张票 ");

    // }

    // }

    // }

    // }

    //同步代码块用任意对象做锁

    // @Override

    // public void run() {

    // while (true) {

    // synchronized (d) {

    // if (tickets > 0) {

    // try {

    // Thread.sleep(100);

    // } catch (InterruptedException e) {

    // e.printStackTrace();

    // }

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

    // + "正在出售第" + (tickets--) + "张票 ");

    // }

    // }

    // }

    // }

    @Override

    public void run() {

    while (true) {

    if(x%2==0){

    synchronized (SellTicket.class) {

    if (tickets > 0) {

    try {

    Thread.sleep(100);

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

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

    + "正在出售第" + (tickets--) + "张票 ");

    }

    }

    }else {

    // synchronized (d) {

    // if (tickets > 0) {

    // try {

    // Thread.sleep(100);

    // } catch (InterruptedException e) {

    // e.printStackTrace();

    // }

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

    // + "正在出售第" + (tickets--) + "张票 ");

    // }

    // }

    sellTicket();

    }

    x++;

    }

    }


    // private void sellTicket() {

    // synchronized (d) {

    // if (tickets > 0) {

    // try {

    // Thread.sleep(100);

    // } catch (InterruptedException e) {

    // e.printStackTrace();

    // }

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

    // + "正在出售第" + (tickets--) + "张票 ");

    // }

    // }

    // }

    //如果一个方法一进去就看到了代码被同步了,那么我就再想能不能把这个同步加在方法上呢?

    //  private synchronized void sellTicket() {

    // if (tickets > 0) {

    // try {

    // Thread.sleep(100);

    // } catch (InterruptedException e) {

    // e.printStackTrace();

    // }

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

    // + "正在出售第" + (tickets--) + "张票 ");

    // }

    // }

    private static synchronized void sellTicket() {

    if (tickets > 0) {

    try {

    Thread.sleep(100);

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

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

    + "正在出售第" + (tickets--) + "张票 ");

    }

    }

    }


    class Demo {

    }

    package cn.itcast_11;(2)


    /*

     * A:同步代码块的锁对象是谁呢?

     *  任意对象。

     * 

     * B:同步方法的格式及锁对象问题?

     *  把同步关键字加在方法上。

     * 

     *  同步方法是谁呢?

     *  this

     * 

     * C:静态方法及锁对象问题?

     *  静态方法的锁对象是谁呢?

     *  类的字节码文件对象。(反射会讲)

     */

    public class SellTicketDemo {

    public static void main(String[] args) {

    // 创建资源对象

    SellTicket st = new SellTicket();


    // 创建三个线程对象

    Thread t1 = new Thread(st, "窗口1");

    Thread t2 = new Thread(st, "窗口2");

    Thread t3 = new Thread(st, "窗口3");


    // 启动线程

    t1.start();

    t2.start();

    t3.start();

    }

    }



    (12)回顾以前的线程安全的类

    A:StringBuffer

    B:Vector

    C:Hashtable

    D:如何把一个线程不安全的集合类变成一个线程安全的集合类

    用Collections工具类的方法即可。


    package cn.itcast_12;


    import java.util.ArrayList;

    import java.util.Collections;

    import java.util.Hashtable;

    import java.util.List;

    import java.util.Vector;


    public class ThreadDemo {

    public static void main(String[] args) {

    // 线程安全的类

    StringBuffer sb = new StringBuffer();

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

    Hashtable<String, String> h = new Hashtable<String, String>();


    // Vector是线程安全的时候才去考虑使用的,但是我还说过即使要安全,我也不用你

    // 那么到底用谁呢?

    // public static <T> List<T> synchronizedList(List<T> list)

    List<String> list1 = new ArrayList<String>();// 线程不安全

    List<String> list2 = Collections

    .synchronizedList(new ArrayList<String>()); // 线程安全

    }

    }




    扩展::



    1:要想了解多线程,必须先了解线程,而要想了解线程,必须先了解进程,因为线程是依赖于进程而存在。


    2:什么是进程?

    通过任务管理器我们就看到了进程的存在。

    而通过观察,我们发现只有运行的程序才会出现进程。

    进程:就是正在运行的程序。

    进程是系统进行资源分配和调用的独立单位。每一个进程都有它自己的内存空间和系统资源。

    3:多进程有什么意义呢?

    单进程的计算机只能做一件事情,而我们现在的计算机都可以做多件事情。

    举例:一边玩游戏(游戏进程),一边听音乐(音乐进程)。

    也就是说现在的计算机都是支持多进程的,可以在一个时间段内执行多个任务。

    并且呢,可以提高CPU的使用率。

    问题:

    一边玩游戏,一边听音乐是同时进行的吗?

    不是。因为单CPU在某一个时间点上只能做一件事情。

    而我们在玩游戏,或者听音乐的时候,是CPU在做着程序间的高效切换让我们觉得是同时进行的。

    4:什么是线程呢?

    在同一个进程内又可以执行多个任务,而这每一个任务我就可以看出是一个线程。

    线程:是程序的执行单元,执行路径。是程序使用CPU的最基本单位。

    单线程:如果程序只有一条执行路径。

    多线程:如果程序有多条执行路径。

    5:多线程有什么意义呢?

    多线程的存在,不是提高程序的执行速度。其实是为了提高应用程序的使用率。

    程序的执行其实都是在抢CPU的资源,CPU的执行权。

    多个进程是在抢这个资源,而其中的某一个进程如果执行路径比较多,就会有更高的几率抢到CPU的执行权。

    我们是不敢保证哪一个线程能够在哪个时刻抢到,所以线程的执行有随机性。



    Java帮帮今日头条号



    Java帮帮微信公众号



    Java帮帮交流群

    展开全文
  • 这篇开始学习Thread类相关方法,先来看看给线程设置名称和获取名称的方法。打开Thread API文档,找到getName()和setName()方法。我们先来看看获取线程名称方法,然后看看设置线程名称方法。 1.获取线程名称getName...

    这篇开始学习Thread类相关方法,先来看看给线程设置名称和获取名称的方法。打开Thread API文档,找到getName()和setName()方法。我们先来看看获取线程名称方法,然后看看设置线程名称方法。

    1.获取线程名称getName()方法

    下面采用前面一篇介绍的匿名类来写线程代码。

    package thread;
    
    public class Demo4_Thread {
    
    	public static void main(String[] args) {
    		
    		new Thread() {
    			public void run() {
    				System.out.println(this.getName() +": aaaaaa");
    			}
    		}.start();
    		
    		new Thread() {
    			public void run() {
    				System.out.println(this.getName() +": bbbbb");
    			}
    		}.start();
    	}
    
    }
    

    运行结果:

    Thread-0: aaaaaa
    Thread-1: bbbbb

    看运行结果,如果多线程不给设置名称,那么会自动给设置Thread-0的格式的名称,从0到N。下面我们,看看如何给线程设置名称。

    2.通过构造方法给线程设置名称

    package thread;
    
    public class Demo4_Thread {
    
    	public static void main(String[] args) {
    		
    		new Thread("线程1") {
    			public void run() {
    				System.out.println(this.getName() +": aaaaaa");
    			}
    		}.start();
    		
    		new Thread("线程2") {
    			public void run() {
    				System.out.println(this.getName() +": bbbbb");
    			}
    		}.start();
    	}
    
    }
    

    输出结果:

    线程1: aaaaaa
    线程2: bbbbb

    3.通过setName()方法设置线程名称

    package thread;
    
    public class Demo4_Thread {
    
    	public static void main(String[] args) {
    		
    		new Thread() {
    			public void run() {
    				this.setName("线程A");
    				System.out.println(this.getName() +": aaaaaa");
    			}
    		}.start();
    		
    		new Thread() {
    			public void run() {
    				this.setName("线程B");
    				System.out.println(this.getName() +": bbbbb");
    			}
    		}.start();
    	}
    
    }
    

    运行结果:

    线程A: aaaaaa
    线程B: bbbbb

     

    展开全文
  • logcat带线程名及id

    千次阅读 2018-10-13 02:07:09
  • adb logcat 带线程名和id

    千次阅读 2018-10-12 17:06:00
    __VA_ARGS__:格式化参数列表 例子: __android_log_print(ANDROID_LOG_DEBUG,"libAirplay", "service URI : %s", "www.163.com.video.xixi.mp4"); 3) 直接使用并不是个好的想法,如果能够可以和eclipse...

    将以下3者结合,写一个Log宏,随便加随便打。如下:

    
    ///
    //personal debug switch// 
    /********************************************************************************
    P_DEBUG:
    0     turn off debug 
    1	    turn on debug 
     ********************************************************************************/
    #ifndef P_LOGI 
    #ifndef _PTHREAD_H_
    #include <pthread.h>
    //#define _PTHREAD_H_
    #endif
    
    #include "utils/Log.h"
    #define P_DEBUG	1
    #if P_DEBUG
    static char mark_label[64] = "pmain";
    #define SEPARATOR_LINE "----------------------------------"
          #define STA_LINE ">>>>>>>>>>>>>>>>>>>>>>>>>>>st.func"
          #define END_LINE "<<<<<<<<<<<<<<<<<<<<<<<<<<<ed.func"
    #define LONNG_LINE = "------------------------------------------------------------------------------"
    //static char mark_label[18] = "";//for the label you wish to mark when you adb logcat or whatever
    #define P_LOGI(fmt, ...) ALOGI("Th%u,%s-,F:%s:%d, Fuc:%s  " fmt,(unsigned int)pthread_self(),mark_label,(char*)__FILE__,__LINE__,(char*)__FUNCTION__,##__VA_ARGS__)
    //#define P_LOGI(fmt, ...) printf("%s-,F:%s:%d, Fuc:%s  " fmt,mark_label,(char*)__FILE__,__LINE__,(char*)__FUNCTION__,##__VA_ARGS__)
    #else
    #define P_LOGI(...)
    #endif
    
    #endif
    
    ///
        //P_LOGI(SEPARATOR_LINE);
    ///

     

     

     

    std::this_thread::get_id();

    or

    GetCurrentThreadId();

     

     

    线程相关函数(2)-pthread_self()获取调用线程ID

    获取调用线程tid

    #include <pthread.h>
    pthread_t pthread_self(void);

    示例:

    复制代码

    #include <pthread.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    
    void *printids(void *arg)
    {
        const char *str = (const char *)arg;
    
        pid_t pid;
        pthread_t tid;
        
        pid = getpid();
        tid = pthread_self();
        printf("%s pid %u tid %u (0x%x)\n", str, (unsigned int)pid, (unsigned int)tid, (unsigned int)tid);
        
    }
    
    
    
    
    int main()
    {    
    
        pthread_t tid;
        int err;    
    
        err = pthread_create(&tid, NULL, printids, "new thread: ");
        if (err != 0) {
            fprintf(stderr, "can't create thread: %s\n", strerror(err));
            exit(1);
        }    
        printids("main thread: ");    
        sleep(1);
        return 0;
    
    }

    复制代码

    运行结果:

    main thread: pid 4959 tid 9791296 (0x956740)
    new thread: pid 4959 tid 1480448 (0x169700)

     

     

    logcat命令学习好文章:

    http://blog.csdn.net/hudashi/article/details/7062914

     一、 如何将C++的标准输出打印到logcat中

    在default状态下调用printf等std C/C++接口输出的log不会被打印到eclipse的logcat中,

    但是android提供了__android_log_print这个函数可以将log重定向到eclipse的logcat中.

     

    1)      在对应的mk文件中加入:LOCAL_LDLIBS := -llog

    2)      在要使用LOG的cpp文件中加入:
    #include <android/log.h>

    使用方法如下;
    __android_log_print(ANDROID_LOG_DEBUG,"Tag", __VA_ARGS__)

    ANDROID_LOG_DEBUG: log的level

    Tag:module的tag

    __VA_ARGS__:格式化参数列表

    例子:

    __android_log_print(ANDROID_LOG_DEBUG,"libAirplay",  "service URI : %s", "www.163.com.video.xixi.mp4");

    3)      直接使用并不是个好的想法,如果能够可以和eclipse一样实现分等级打印,那还不错;实现如下:

    #define LOGV(...)__android_log_print(ANDROID_LOG_VERBOSE, " Tag", __VA_ARGS__)   // VERBOSE
    #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG , " Tag ", __VA_ARGS__)    // DEBUG
    #define LOGI(...) __android_log_print(ANDROID_LOG_INFO  , " Tag ",__VA_ARGS__)          // INFO
    #define LOGW(...) __android_log_print(ANDROID_LOG_WARN  , " Tag ", __VA_ARGS__)    //WARN
    #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR  , " Tag ",__VA_ARGS__)      // ERROR

     

    注意:括号中是省略号,不用改为参数.

    在需要的地方直接使用

    LOGV(“www.163.com.video.xixi.mp4”);

    或者LOGD(“www.163.com.video.xixi.mp4”); 就好

    4)      使用以上的函数打印出的log会出现在eclipse中(前提是:devices已经和PC adb connect了).

    其他资料:

    如何在shell下将printf打印的信息定向到logcat中:

    touch /data/local.prop

    vi local.prop   输入log.redirect=true

    重启

    logcat stdout:* stderr:*  *:s

    之后就可以看到printf的输出了

     

    或者

    adb shell stop  

    adb shell setprop log.redirect-stdio true

    adb shell start

     

     

     

    二、 如何输出Jni 接口中LOGV 信息。

    在调试android cts问题时, isIEffectCommandSecure 接口中ALOGV("transact status: %d", status);

    不会被打印, 看了下面文章才明白。

    http://blog.csdn.net/mike8825/article/details/49386725

     Android的编译参数中,加入了-DNDEBUG,也就是默认是no debug的,当然还需要LOG_NDEBUG LOG_NIDEBUG LOG_NDDEBUG这三个宏设置。
    当-DNDEBUG被打上后,默认ALOGV会被禁止。

    在log.h中可以看到

    #ifndef LOG_NDEBUG
    #ifdef NDEBUG
    #define LOG_NDEBUG 1
    #else
    #define LOG_NDEBUG 0
    #endif
    #endif

     

    #ifndef ALOGV
    #define __ALOGV(...) ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
    #if LOG_NDEBUG
    #define ALOGV(...) do { if (0) { __ALOGV(__VA_ARGS__); } } while (0)
    #else
    #define ALOGV(...) __ALOGV(__VA_ARGS__)
    #endif
    #endif

    因此, 可以在当前文件的最前面 加入 如下定义, 这样就可以输出

    打开ALOGV: #define LOG_NDEBUG 0
    ---------------------  
    作者:victor_wys  
    来源:CSDN  
    原文:https://blog.csdn.net/wys7250578/article/details/18841923?utm_source=copy  
    版权声明:本文为博主原创文章,转载请附上博文链接!

    展开全文
  • 前不久连续收到Java线程数量过多的报警, 通过 Jstack 工具导出生产环境服务器的线程快照后, 通过分析 dump 文件, 很快就确定了问题。 以前没有排查线上线程数量问题的实战经验, 因此想借助这次机会, 从 thread dump ...
  • Java多线程

    万次阅读 多人点赞 2021-06-11 16:28:49
    Java多线程Java多线程线程的创建线程常见方法线程的状态线程的优先级守护线程线程组Java线程池线程池的创建线程池的参数线程池的使用线程不安全问题Java中的锁synchronized同步方法synchronized同步语句块...
  • log4j打印出线程号和方法

    千次阅读 2019-06-16 22:55:56
    最近写了一些Java多线程的程序,学到log4j打印出线程号和方法,分享一下~ 使用 %t 就可以打印线程名称,这样开发的时候就可以看到线程执行情况了; 先参考实现配置,如果想要更加详细的配置,可加上更多参数: log4j....
  • 线程

    千次阅读 2019-05-30 22:50:07
    线程与进程: 线程:是指程序的运行流程。多线程机制可以同时运行多个程序块,使程序的运行的效率更快。 进程:一个由操作系统分配的内存空间,包含一个或多个线程。 理解线程与进程: 打开一个微博客户端就是打开了...
  •  类,三个线程每一个都有一个信号量,信号量等于 0 将被阻塞,等于 1 可以运行,因为每次只能有一个线程在运行,因此信号量总和应该为 1 ,相当于一个令牌在传递一样。代码如下: private static void ...
  • 内核线程 VS 用户线程

    千次阅读 2019-01-14 16:43:36
    一 用户线程和内核线程概述 在传统的操作系统中,拥有资源和独立调度的基本单位都是进程。在引入线程的操作系统中,线程是独立调度的基本单位,进程是资源拥有的基本单位。在同一进程中,线程的切换不会引起进程...
  • Python 多线程线程间通信

    千次阅读 2020-09-05 17:27:00
    一个线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每个线程并行执行不同的任务。 由于线程是操作系统直接支持的执行单元,因此,高级语言(如 Python、Java 等)通常都内置多线程的支持。...
  • 线程安全

    千次阅读 2018-05-07 23:37:44
    实现线程安全的方式:同步机制两个或两个以上的线程在同时操作一个共享资源时仍然能得到正确的结果,则称为线程安全。判断一个程序是否会有线程安全问题的标准 A:是否是多线程环境 B:是否有共享数据 C:是否有多...
  • 基础——线程

    千次阅读 2020-06-25 17:42:23
    1、线程的内存原理 2、线程的创建 3、线程的安全 4、线程的状态 5、生产者消费者模式 6、双线程交替执行
  • JAVA 多线程

    千次阅读 2021-04-03 21:19:04
    线程 在看多线程之前先来看看必要的一些东西: 线程与进程 进程: 是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间。 线程: 是进程中的一个执行路径,共享一个内存空间,线程之间可以自由切换,...
  • 解决多线程导致的线程安全问题: 1:同步代码块 格式: synchronized(锁对象)... 权限修饰符 synchronized 返回值类型 方法(参数){ 可以会出现线程安全问题的代码(访问了共享数据的代码) } 使用步骤: 将访问
  • 格式如下 复制代码 代码如下: threading.Thread(group=None, target=None, name=None, args=(), kwargs={}) 这个构造器必须用关键字传参调用 – group 线程组 – target 执行方法 – name 线程名字 – args ...
  • 线程:多线程则指的是在单个程序中可以同时运行多个不同的线程执行不同的任务.线程是程序内的顺序控制流,只能使用分配给程序的资源和环境。多线程编程的目的,就是"最大限度地利用CPU资源",当某一线程...
  • C#多线程编程

    千次阅读 2014-06-14 11:47:27
    本文主要从线程的基础用法,CLR线程池当中工作者线程与I/O线程的开发,并行操作PLINQ等多个方面介绍多线程的开发。 其中委托的BeginInvoke方法以及回调函数最为常用。 而 I/O线程可能容易遭到大家的忽略,其实在...
  • Java线程——线程控制基本方法

    千次阅读 2018-08-03 17:54:29
    线程操作基本方法 isAlive() 判断线程是否还未终止 ...调用某线程的该方法,将当前线程与该线程“合并”,等待该线程结束,再恢复当前线程的运行 yield() 让出cpu,当前线程进入就绪队列等待调度 wai...
  • 进程和线程的概念、区别及进程线程间通信

    千次阅读 多人点赞 2020-08-02 16:24:25
    进程与线程的概念,以及为什么要有进程线程,其中有什么区别,他们各自又是怎么同步的? 1. 基本概念: 进程是对运行时程序的封装,是系统进行资源调度和分配的的基本单位,实现了操作系统的并发; 线程是进程的子...
  • 首先整理多线程同步的知识点,开头肯定是要先探讨探讨多线程同步的问题。那么嘛叫线程安全问题呢? 答: 我们知道Jvm虚拟机的设计中线程的执行是抢占式的,线程的执行时间是由底层系统决定的。所以就会有多个线程...
  • JAVA线程线程、进程与进程间通信

    万次阅读 2016-07-11 10:54:31
    线程线程间通信 一、多线程间通信方式: 1、共享变量 2、wait/notify机制 3、Lock/Condition机制 二、共享变量 线程间发送信号的一个简单方式是在共享对象的变量里设置信号值。线程A在一个同步块里设置boolean型...
  • 线程面试题总结

    千次阅读 多人点赞 2019-06-11 00:04:49
    线程面试题总结 什么是线程线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位,可以使用多线程对进行运算提速。 比如,如果一个线程完成一个任务要100毫秒,那么用十个线程...
  • 线程基础

    千次阅读 2020-09-30 21:17:45
    文章目录一、多线程1. 1 并发与并行1. 2 线程与进程1. 3 Thread创建线程1. 4 Runnable创建线程1. 5 匿名内部类创建线程二、线程安全2. 1 Java内存模型(JMM)2. 2 线程安全2. 2 线程同步三、生命周期3. 1 概述3. 2 ...
  • 地址:http://blog.csdn.net/u013357243?viewmode=contents一:NSThread的基本使用1:创建和启动线程一个NSThread对象就代表一条线程创建、启动线程NSThread *thread = [[NSThread alloc] initWithTarget:self ...
  • java多线程详细理解

    千次阅读 多人点赞 2021-02-14 21:10:51
    明确一点:多线程不是为了提高程序执行速度(性能甚至更低),而是提高应用程序的使用效率。 多线程的三大特性:原子性、可见性、有序性 一、创建线程 创建线程额的开销:分配内存 --> 列入调度 --> 线程切换...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 303,387
精华内容 121,354
关键字:

线程名格式