精华内容
下载资源
问答
  • 线程创建方式的区别

    2018-08-03 20:06:30
    通常情况下,线程创建方式有如下2种,它们的区别如下: 线程创建方式的区别 继承Thread类 实现Runable接口 用this直接指代当前线程对象 必须使用Thread.currentThread()去获取当前线程对象 创建的Thread...

    通常情况下,线程创建方式有如下2种,它们的区别如下:

    线程创建方式的区别
    继承Thread类 实现Runable接口
    用this直接指代当前线程对象 必须使用Thread.currentThread()去获取当前线程对象
    创建的Thread子类对象即可代表线程对象,例如:new FirstThread().start() 创建的Runnable对象即只能作为线程对象的target,例如:new Thread(new SecondThread(),"线程2").start()
    多个线程之间不能共享线程类的实例变量 多个线程之间可以共享线程类(实际上应该是线程的target类)的实例变量
    不可以再继承其他类了 还可以继承其他类
      多个线程可以共享同一个target对象,非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU、代码和数据分开,形成清晰的模型,较好地体现“面向对象”的思想

    综上所述,通常使用实现Runnable接口的方式来创建线程。

    展开全文
  • 线程创建方式 1.使用 Thread(Runnable target)这个构造方法创建Thread对象,传入一个实现Runnable接口的对象。实现Runnable接口要实现Run方法,所以这种方法创建的线程运行时,会执行这个Runnable接口上的Run方法。...
    线程创建方式
    1.使用 Thread(Runnable target)这个构造方法创建Thread对象,传入一个实现Runnable接口的对象。实现Runnable接口要实现Run方法,所以这种方法创建的线程运行时,会执行这个Runnable接口上的Run方法。
    2.定义Thread子类,重写run方法,当这个线程执行时,会执行已重写的run方法。
    面试题:以下代码的输出语句是
    <span style="font-size:18px;">publicclassThreadTest {
    
    
         public static void main(String[] args) {
               Thread thread = new Thread( new Runnable() {
                     // 在Thread的构造方法中传入Runnable对象,thread运行时,会执行这个 Runalbe内的run方法。
                     @Override
                     public void run() {
                         System. out.println( "Thread中Runnable对象的run方法" );
                    }
               }) {
                     // Thread的子类,重写父类的run方法,thread运行时,会执行子类上重写的run方法。
                     @Override
                     public void run() {
                         System. out.println( "Thread子类的run方法" );
                    }
    
    
               };
                thread.start();
         }
    }</span>

    答案:Thread子类的run方法。Runnable的run方法是在执行父类run方法时才会被调用的,在源代码中是这样写的:
    <span style="font-size:18px;"> public void run() {
            if (target != null) {
                target.run();
            }
        }</span>

    但是匿名子类重写了父类的run方法,所以父类的run方法并不会被执行,因此执行的是子类的run方法。


    线程互斥
    多个线程访问同一数据时,可能会引起数据错乱,为了避免这种情况的出现,加入了互斥技术,也就是在访问共享数据时,加一把锁,防止其他线程进入访问。在java中用synchronized关键字表示。
    synchronized可以修饰方法,表示整个方法加锁。也可以用synchronized(obj)修饰代码块,表示一段代码加锁。
    锁并不都是相同的,只有相同的锁之间才可以互斥。也可以根据锁划分互斥组。
    互斥说明:
    1.使用synchronized(obj)和synchronized(obj1),当obj==obj1时互斥,注意不是equals
    2.synchronized 修饰静态方法,与synchronized(类名.class)互斥
    3.synchronized 修饰非静态方法,与synchronized(this)互斥

    线程间的通信
    多见于一个线程操作数据前,需要其他线程先进行操作的例子。比如消费者-生产者的例子,消费者在消费商品前,必须等待生产者先生产出商品才行。
    这样的问题可以用锁对象的wait,notify和notiyAll方法进行,这样方法分别可以使当前线程等待或使其他线程唤醒。由于锁对象可以是任意对象,所以这些方法被定义在Object类中。

    总结:JDK1.5中提供了多线程升级解决方案
    将synchronized替换成了Lock操作。
    线程间的通信方面,将锁Object中的wait,notify,notifyAll,替换成Condition对象。该对象可以通过Lock对象获取到。
    而且一个Lock对象可以获取到多个Condition对象,这样可以对指定的Condition进行唤醒或等待操作。
    具体使用可以查看API帮助文档,里面有示例代码。
    展开全文
  • 在创建线程时遇到了几种线程创建方式现总结如下:   首先看看boost::thread的构造函数吧,boost::thread有两个构造函数: (1)thread():构造一个表示当前执行线程的线程对象; (2)explicit thread(const ...

    最近在做一个消息中间件里面涉及到多线程编程,由于跨平台的原因我采用了boost线程库。在创建线程时遇到了几种线程创建方式现总结如下: 
      首先看看boost::thread的构造函数吧,boost::thread有两个构造函数:
    (1)thread():构造一个表示当前执行线程的线程对象;
    (2)explicit thread(const boost::function0<void>& threadfunc):
         boost::function0<void>可以简单看为:一个无返回(返回void),无参数的函数。这里的函数也可以是类重载operator()构成的函数;该构造函数传入的是函数对象而并非是函数指针,这样一个具有一般函数特性的类也能作为参数传入,在下面有例子。


    第一种方式:最简单方法
    #include <boost/thread/thread.hpp>
    #include <iostream>
     
    void hello()
    {
            std::cout <<
            "Hello world, I''m a thread!"
            << std::endl;
    }
     
    int main(int argc, char* argv[])
    {
            boost::thread thrd(&hello);
            thrd.join();
            return 0;
    }


    第二种方式:复杂类型对象作为参数来创建线程:
    #include <boost/thread/thread.hpp>
    #include <boost/thread/mutex.hpp>
    #include <iostream>
     
    boost::mutex io_mutex;
     
    struct count
    {
            count(int id) : id(id) { }
           
            void operator()()
            {
                    for (int i = 0; i < 10; ++i)
                    {
                            boost::mutex::scoped_lock
                            lock(io_mutex);
                            std::cout << id << ": "
                            << i << std::endl;
                    }
            }
           
            int id;
    };
     
    int main(int argc, char* argv[])
    {
            boost::thread thrd1(count(1));
            boost::thread thrd2(count(2));
            thrd1.join();
            thrd2.join();
            return 0;
    }


    第三种方式:在类内部创建线程;
    (1)类内部静态方法启动线程
    #include <boost/thread/thread.hpp>
    #include <iostream>
    class HelloWorld
    {
    public:
     static void hello()
     {
          std::cout <<
          "Hello world, I''m a thread!"
          << std::endl;
     }
     static void start()
     {
     
      boost::thread thrd( hello );
      thrd.join();
     }
     
    };
    int main(int argc, char* argv[])
    {
     HelloWorld::start();
     
     return 0;
    }
    在这里start()和hello()方法都必须是static方法。


    (2)如果要求start()和hello()方法不能是静态方法则采用下面的方法创建线程:
    #include <boost/thread/thread.hpp>
    #include <boost/bind.hpp>
    #include <iostream>
    class HelloWorld
    {
    public:
     void hello()
     {
        std::cout <<
        "Hello world, I''m a thread!"
        << std::endl;
     }
     void start()
     {
      boost::function0< void> f =  boost::bind(&HelloWorld::hello,this);
      boost::thread thrd( f );
      thrd.join();
     }
     
    };
    int main(int argc, char* argv[])
    {
     HelloWorld hello;
     hello.start();
     return 0;
    }


    (3)在Singleton模式内部创建线程:
    #include <boost/thread/thread.hpp>
    #include <boost/bind.hpp>
    #include <iostream>
    class HelloWorld
    {
    public:
     void hello()
     {
        std::cout <<
        "Hello world, I''m a thread!"
        << std::endl;
     }
     static void start()
     {
      boost::thread thrd( boost::bind 
                       (&HelloWorld::hello,&HelloWorld::getInstance() ) ) ;
      thrd.join();
     }
     static HelloWorld& getInstance()
     {
      if ( !instance )
          instance = new HelloWorld;
      return *instance;
     }
    private:
     HelloWorld(){}
     static HelloWorld* instance;
     
    };
    HelloWorld* HelloWorld::instance = 0;
    int main(int argc, char* argv[])
    {
     HelloWorld::start();

     return 0;
    }


    第四种方法:用类内部函数在类外部创建线程;
    #include <boost/thread/thread.hpp>
    #include <boost/bind.hpp>
    #include <string>
    #include <iostream>
    class HelloWorld
    {
    public:
     void hello(const std::string& str)
     {
            std::cout <<str<< std::endl;
     }
    };
     
    int main(int argc, char* argv[])
    {
     HelloWorld obj;
     boost::thread thrd( boost::bind(&HelloWorld::hello,&obj,"Hello
                                   world, I''m a thread!" ) ) ;
     thrd.join();
     return 0;
    }


    如果线程需要绑定的函数有参数则需要使用boost::bind。比如想使用 boost::thread创建一个线程来执行函数:void f(int i),如果这样写:boost::thread thrd(f)是不对的,因为thread构造函数声明接受的是一个没有参数且返回类型为void的型别,而且不提供参数i的值f也无法运行,这时就可以写:boost::thread thrd(boost::bind(f,1))。涉及到有参函数的绑定问题基本上都是boost::thread、boost::function、boost::bind结合起来使用。

    展开全文
  • 一:创建线程方式:1. 继承Thread,然后重写run()方法例如: public class ThreadOne extends Thread { @Override public void run() { Log.i("TAG","创建线程方式1"); }}启动线程方式...
    一:创建线程方式:
    1.  继承Thread,然后重写run()方法
    例如: 
    public class ThreadOne extends Thread {
        @Override
        public void run() {
            Log.i("TAG","创建线程方式1");
        }
    }


    启动线程方式start
     ThreadOne one = new ThreadOne();
            one.start();


    2.实现runable接口
    例如:
    public class ThreadTwo implements Runnable {
        @Override
        public void run() {
            Log.i("TAG","创建线程方式2");
        }
    }
     Thread thread = new Thread(new ThreadTwo());
            thread.start();
    3.通过Callable和Future创建线程


    public class FetureThread implements Callable<Integer> {
        int a = 0;


        @Override
        public Integer call() throws Exception {
            for(int i = 0 ; i < 8; i++ ){
                a++;
            }
            return a;
        }
    }


    public class Future {
        FetureThread fetureThread = new FetureThread();
        FutureTask<Integer> task = new FutureTask<Integer>(fetureThread);
        public void run(){
          Thread t = new Thread(task);
            t.start();
        }
        public Integer getResult(){
            try {
                return  task.get();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
            return 0;
        }
    }


    Future future = new Future();
            future.run();
            Log.i("HomeActivity 线程执行结果",future.getResult()+"");
    以上三种创建线程的方式比较:


    使用继承Thread类的方式创建多线程时优势是:


    编写简单,如果需要访问当前线程
    线程类已经继承了Thread类,所以不能再继承其他父类
    采用实现Runnable、Callable接口的方式创见多线程时,优势是:


    线程类只是实现了Runnable接口或Callable接口,还可以继承其他类,同时使用Callable
    还可以获取线程执行的结果
    二:线程同步方式:
    1.synchronized,
    当用此关键字修饰方法时, 内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。
    注: synchronized关键字也可以修饰静态方法,此时如果调用该静态方法,将会锁住整个类。
    :同步是一种高开销的操作,因此应该尽量减少同步的内容。通常没有必要同步整个方法,使用synchronized代码块同步关键代码即可。


    public class MoneyThread implements Runnable {


        @Override
        public void run() {
            synchronized (this){
                for(int i = 0; i < 10 ;i++){
                    Log.i("HomeActivity " +"执行结果"+ Thread.currentThread().getName(),(++i)+"");
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }


        }
    }


    MoneyThread moneyThread = new MoneyThread();
            Thread t1 = new Thread(moneyThread,"线程1");
            t1.start();
            Thread t2 = new Thread(moneyThread,"线程2");
            t2.start();


    执行结果:


      执行结果线程1: 1
    01-14 22:22:25.957 21985-22005/? I/HomeActivity 执行结果线程1: 3
    01-14 22:22:25.967 21985-22005/? I/HomeActivity 执行结果线程1: 5
    01-14 22:22:25.967 21985-21985/? D/InputTransport: Input channel constructed: name='440c7c98 com.examply (client)', fd=57
    01-14 22:22:25.977 21985-22005/? I/HomeActivity 执行结果线程1: 7
    01-14 22:22:25.987 21985-22005/? I/HomeActivity 执行结果线程1: 9
    01-14 22:22:26.007 21985-22006/? I/HomeActivity 执行结果线程2: 1
    01-14 22:22:26.017 21985-22006/? I/HomeActivity 执行结果线程2: 3
    01-14 22:22:26.027 21985-22006/? I/HomeActivity 执行结果线程2: 5
    01-14 22:22:26.037 21985-22006/? I/HomeActivity 执行结果线程2: 7
    01-14 22:22:26.052 21985-22006/? I/HomeActivity 执行结果线程2: 9


    当两个并发线程(thread1和thread2)访问同一个对象(syncThread)中的synchronized代码块时,
    在同一时刻只能有一个线程得到执行,另一个线程受阻塞,必须等待当前线程执行完这个代码
    块以后才能执行该代码块。Thread1和thread2是互斥的,因为在执行synchronized代码块时会
    锁定当前的对象,只有执行完该代码块才能释放该对象锁,下一个线程才能执行并锁定该对象


    我们稍作修改:


     Thread t1 = new Thread(new MoneyThread(),"线程1");
            t1.start();
            Thread t2 = new Thread(new MoneyThread(),"线程2");
            t2.start();

    执行结果:
    01-14 22:28:35.572 28140-28159/? I/HomeActivity 执行结果线程1: 1
    01-14 22:28:35.572 28140-28160/? I/HomeActivity 执行结果线程2: 1
    01-14 22:28:35.582 28140-28160/? I/HomeActivity 执行结果线程2: 3
    01-14 22:28:35.582 28140-28159/? I/HomeActivity 执行结果线程1: 3
    01-14 22:28:35.587 28140-28140/? D/InputTransport: Input channel constructed: name='45044e78 com.example.yybj.myapplication/com.example.yybj.myapplication.HomeActivity (client)', fd=57
    01-14 22:28:35.592 28140-28160/? I/HomeActivity 执行结果线程2: 5
    01-14 22:28:35.592 28140-28159/? I/HomeActivity 执行结果线程1: 5
    01-14 22:28:35.602 28140-28160/? I/HomeActivity 执行结果线程2: 7
    01-14 22:28:35.602 28140-28159/? I/HomeActivity 执行结果线程1: 7
    01-14 22:28:35.612 28140-28160/? I/HomeActivity 执行结果线程2: 9
    01-14 22:28:35.612 28140-28159/? I/HomeActivity 执行结果线程1: 9




    不是说一个线程执行synchronized代码块时其它的线程受阻塞吗?为什么上面的
    例子中thread1和thread2同时在执行。这是因为synchronized只锁定对象,
    每个对象只有一个锁(lock)与之相关联


    这时创建了两个SyncThread的对象syncThread1和syncThread2,线程thread1执行的是
    syncThread1对象中的synchronized代码(run),而线程thread2执行的是syncThread2对象
    中的synchronized代码(run);我们知道synchronized锁定的是对象,这时会有两把锁分别锁定
    syncThread1对象和syncThread2对象,而这两把锁是互不干扰的,不形成互斥,
    所以两个线程可以同时执行


    2.给指定的对象加锁:
    public class OpeateThread implements Runnable {
        Money money;


        public OpeateThread(Money money) {
            this.money = money;
        }


        @Override
        public void run() {
            try {
                synchronized (money){
                    money.save(500);
                    money.getMoney(500);
                    Log.i("HomeActivity " +"执行结果"+ Thread.currentThread().getName(),
                            "现在的账户余额"+money.getResult()+"");
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


     Money account = new Money(10000,"李四");
            OpeateThread accountOperator = new OpeateThread(account);


            final int THREAD_NUM = 5;
            Thread threads[] = new Thread[THREAD_NUM];
            for (int i = 0; i < THREAD_NUM; i ++) {
                threads[i] = new Thread(accountOperator, "线程" + i);
                threads[i].start();
            }


    执行结果:
    96-9540/com.example.yybj.myapplication I/HomeActivity 执行结果线程0: 现在的账户余额10000
    01-14 22:42:03.917 9496-9544/com.example.yybj.myapplication I/HomeActivity 执行结果线程4: 现在的账户余额10000
    01-14 22:42:03.937 9496-9542/com.example.yybj.myapplication I/HomeActivity 执行结果线程2: 现在的账户余额10000
    01-14 22:42:03.957 9496-9541/com.example.yybj.myapplication I/HomeActivity 执行结果线程1: 现在的账户余额10000
    01-14 22:42:03.977 9496-9543/com.example.yybj.myapplication I/HomeActivity 执行结果线程3: 现在的账户余额10000




    当有一个明确的对象作为锁时,就可以用类似下面这样的方式写程序。
    public void method3(SomeObject obj)
    {
       //obj 锁定的对象
       synchronized(obj)
       {
          // todo
       }
    }


    当没有明确的对象作为锁,只是想让一段代码同步时,可以创建一个特殊的对象来充当锁:


    class Test implements Runnable
    {
       private byte[] lock = new byte[0];  // 特殊的instance变量
       public void method()
       {
          synchronized(lock) {
             // todo 同步代码块
          }
       }


       public void run() {


       }
    }


    说明:零长度的byte数组对象创建起来将比任何对象都经济――查看编译后的字节码:
    生成零长度的byte[]对象只需3条操作码,而Object lock = new Object()则需要7行操作码。




    修饰一个方法


    Synchronized作用于整个方法的写法。 
    写法一:


    public synchronized void method()
    {
       // todo
    }


    写法二:


    public void method()
    {
       synchronized(this) {
          // todo
       }
    }
    写法一修饰的是一个方法,写法二修饰的是一个代码块,
    但写法一与写法二是等价的,都是锁定了整个方法时的内容




    修饰一个静态的方法
    Synchronized也可修饰一个静态方法,用法如下:


    public synchronized static void method() {
       // todo
    }


    我们知道静态方法是属于类的而不属于对象的。同样的,synchronized修饰的静态方
    法锁定的是这个类的所有对象。 




    package com.example.yybj.myapplication;


    import android.util.Log;


    /**
     * Created by YYBJ on 2018/1/14.
     */


    public class StaticMoneyThread implements Runnable {
        private static int a = 0;


        @Override
        public synchronized void run() {
            test();
        }


        private synchronized static void test() {
            for (int i = 0; i < 5; i++) {
                Log.i("HomeActivity " + "执行结果" +
                        Thread.currentThread().getName(), (a += i) + "");
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    执行结果:01-14 23:00:59.877 28433-28467/com.example.yybj.myapplication I/HomeActivity 执行结果线程1: 0
    01-14 23:00:59.887 28433-28467/com.example.yybj.myapplication I/HomeActivity 执行结果线程1: 1
    01-14 23:00:59.887 28433-28433/com.example.yybj.myapplication D/InputTransport: Input channel constructed: name='44083f28 com.example.yybj.myapplication/com.example.yybj.myapplication.HomeActivity (client)', fd=58
    01-14 23:00:59.897 28433-28467/com.example.yybj.myapplication I/HomeActivity 执行结果线程1: 3
    01-14 23:00:59.907 28433-28467/com.example.yybj.myapplication I/HomeActivity 执行结果线程1: 6
    01-14 23:00:59.917 28433-28467/com.example.yybj.myapplication I/HomeActivity 执行结果线程1: 10
    01-14 23:00:59.957 28433-28468/com.example.yybj.myapplication I/HomeActivity 执行结果线程2: 10
    01-14 23:00:59.967 28433-28468/com.example.yybj.myapplication I/HomeActivity 执行结果线程2: 11
                                                                                          
                                                                                          [ 01-14 23:00:59.972 28433:28433 E/         ]
                                                                                          mali: REVISION=Linux-r3p1-01rel1 BUILD_DATE=Tue Jul  2 15:06:24 KST 2013 
    01-14 23:00:59.982 28433-28468/com.example.yybj.myapplication I/HomeActivity 执行结果线程2: 13
    01-14 23:00:59.992 28433-28468/com.example.yybj.myapplication I/HomeActivity 执行结果线程2: 16
    01-14 23:01:00.007 28433-28468/com.example.yybj.myapplication I/HomeActivity 执行结果线程2: 20




    syncThread1和syncThread2是SyncThread的两个对象,但在thread1和thread2并发执行时却保持了线程同步。
    这是因为run中调用了静态方法method,而静态方法是属于类的,所以syncThread1和syncThread2相当于用了同一把锁


    总结:
     无论synchronized关键字加在方法上还是对象上,如果它作用的对象是非静态的,则它取得的锁是对象;
     如果synchronized作用的对象是一个静态方法或一个类,则它取得的锁是对类,该类所有的对象同一把锁。 
    B. 每个对象只有一个锁(lock)与之相关联,谁拿到这个锁谁就可以运行它所控制的那段代码。 
    C. 实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制




    在多线程的情况下,由于同一进程的多个线程共享同一片存储空间,在带来方便的同时,也带来了访问冲突这个严重的问题。
    Java语言提供了专门机制以解决这种冲突,有效避免了同一个数据对象被多个线程同时访问。
     wait与notify是java同步机制中重要的组成部分
     在调用wait的时候,线程自动释放其占有的对象锁,同时不会去申请对象锁。当线程被唤醒的时候,它才再次获得了去获得对象锁的权利。
    wait(),notify(),notifyAll()不属于Thread类,而是属于Object基础类,也就是说每个对像都有wait(),notify(),notifyAll()的功能。
    因为都个对像都有锁,锁是每个对像的基础
    通常,多线程之间需要协调工作:如果条件不满足,则等待;当条件满足时,等待该条件的线程将被唤醒。在Java中,这个机制的实现依
    于wait/notify。等待机制与锁机制是密切关联的。最常见的就是生产者消费者模型
    例如:
      synchronized(obj) {
      while(!condition) {
      obj.wait();
      }
      obj.doSomething();
      }
      
      当线程A获得了obj锁后,发现条件condition不满足,无法继续下一处理,于是线程A就wait()。
      在另一线程B中,如果B更改了某些条件,使得线程A的condition条件满足了,就可以唤醒线程A :
      
      synchronized(obj) {
      condition = true;
      obj.notify();
      }
      
      需要注意的概念是:
      
      # 调用obj的wait(), notify()方法前,必须获得obj锁,也就是必须写在synchronized(obj){...} 代码段内。
      
      # 调用obj.wait()后,线程A就释放了obj的锁,否则线程B无法获得obj锁,也就无法在synchronized(obj){...} 代码段内唤醒A。
      
      # 当obj.wait()方法返回后,线程A需要再次获得obj锁,才能继续执行。
      
      #如果A1,A2,A3都在obj.wait(),则B调用obj.notify()只能唤醒A1,A2,A3中的一个(具体哪一个由JVM决定)。


    线程同步方式2:Lock


    ReentrantLock类 
    作用跟synchronized代码块差不多,都是用于实现互斥,当然两者是有区别的。
    Condition接口 
    它提供了await()、signal()、signalAll()等方法,作用于Object类的wait()、signal()和signalAll()方法一样。
    注意由于它是一个接口,因此是不能new出来的,我们必须通过ReentrantLock类的newCondition方法得到一个
    Condition对象(实际上是ConditionObject类对象),这个对象与该ReentrantLock对象相关联。
    同样,Condition的await()、signal()、signalAll()都必须在获得相对应的ReentrantLock锁才能进行调用


    注意这里我们可以使用同一个ReentrantLock对象多次调用newCondition获得多个Condition对象,以实现更加
    复杂的同步关系,而使用Object类的相当于只能有一个Condition对象。当然,在不同的Condition对象中,
    等待和唤醒要相对应,比如说,我们两次调用newCondition方法,得到了两个Condition对象condition1和condition2,
    假如我在线程A调用condition1.await(),然后线程B调用了condition2.signal(),那么线程A是一定不会因此被唤醒的,
    而应该调用condition1.signal()线程A才可能会被唤醒,为什么说可能而不是一定呢?原因是signal()同Object类的
    notify()是一样的,系统会随机唤醒等待集中的一个线程,而我们的线程A不一定会被选到。


    每次lock完都必须要在finally块中执行unLock。


    线程池:
    线程池+ 阻塞队列综合使用
      ExecutorService executorService =  Executors.newSingleThreadExecutor();
            executorService.submit(new Runnable() {
                @Override
                public void run() {
                    Log.i("HomeActivity","线程池使用----------");
                }

            });

    这个是线程池的核心:



    重点看下Worker;



    所以在向线程池里面添加任务的时候,如果小于核心线程数的话,那就线程池会继续创建线程,如果超过了核心线程数

    那么就会把新到来的任务添加到阻塞队列,当阻塞队列添加满了的时候(ArrayBlockingQueue因为有容量),还有新的任务

    到来的时候就会继续创新新的线程,如果此时线程池里面线程数量小于最大线程数的话,如果还有新的任务到来,就会拒绝

    所以在线程池里面创建线程的时候,线程数量和核心线程数,最大线程数,阻塞队列都有关系.

    所以我们在创建线程池的时候,推荐使用ThreadPoolExecutor()这种方式来创建线程池,这样子开发者可以很清楚的知道线程池里面每一个参数的含义,对于Executors这种方式创建线程池的时候,不推荐,其中newFixedThreadPool,newSingleThreadExecutor,这两种创建线程池的时候在任务量很大的时候会导致OOM,根本原因就是阻塞队列采用的是LinkedBlockingQueue,而LinkedBlockingQueue的大小为Integer.MAX_VALUE,对于,newCachedThreadPool和ScheduledThreadPoolExecutor他们的阻塞队列都不大(这句话不严谨,读者可以看源码就明白了),这种方式创建的线程池,在任务数据多的话,频繁的创建线程,可能会出现OOM,在创建线程的时候要设置线程的名字和group,多打印日志,方便后期对于线程池的分析和系统优化分析.





























































































    展开全文
  • Java多线程创建方式及线程方法

    千次阅读 2020-04-20 22:57:28
    线程创建方式 方式一:继承Thread类 步骤: 1、定义类继承Thread类 2、覆盖Thread类中的run方法 3、调用线程的start方法,该方法两个作用:启动线程、调用run方法 例子: class MyThreadDemo extends Thread { ...
  • 在创建线程时遇到了几种线程创建方式现总结如下:   首先看看boost::thread的构造函数吧,boost::thread有两个构造函数:  (1)thread():构造一个表示当前执行线程的线程对象;  (2)explicit thread...
  • 1.Java的线程初始化  以下介绍一种线程常见的创建方法: 1.1通过继承Thread类、... * 线程创建方式1:继承Thread类 */ public class Demo_extends extends Thread { @Override public void run() { while ...
  • 线程与进程的区别 每个正在系统上运行的程序都是一个进程。每个进程包含一到多个线程线程是一组指令的集合,或者是程序的特殊段,它可以在程序里独立执行。也可以把它理解为代码运行的上下文。所以线程基本上是...
  • 创建线程的3种方式 第一种方式是将类声明为 Thread 的子类。 定义Thread类的子类,并重写该类的run()方法,该run()方法的方法体就代表了线程需要完成的任务,因此把run()方法称为线程执行体。 创建Thread子类的...
  • 创建一个新的线程有两种方式,第一种方式为通过继承Thread类,并实现Thread类中的run()方法。第二种创建线程方式是通过实现Runnable接口来创建一个新的线程。 下面总结一下两种创建线程方式的区别: 从面向对象...
  • 1.创建线程方式 继承thread类 package com.quincy.java.base.threadcreate; public class ThreadCreateOneDriver1 { public static void main(String[] args) { ThreadCreateOneDemo1 threadCreateOneD
  • Thread类和Runnable接口这两种线程创建方式的比较 举例:卖火车票--100张票 使用两种方法:  1.继承Thread类方式实现  2.实现Runnable接口实现 模拟4个售票窗口共同卖100张火车票的程序 第一种继承Thread类...
  • Windows 线程创建方式的比较

    千次阅读 2016-07-14 13:08:53
    进行 Windows 编程时,常需要涉及多线程编程,以下是 Windows 提供的关于创建线程的3个API。
  • 面试题:创建线程有有哪几种方式? 回答:4种。 实现Runnable接口(重写Run方法) 继承Thread类 实现Callable接口(重写Call方法,与Run不同的是,Call方法有返回值) 使用线程池 JDK5.0新增创建线程方式一:...
  • * dcs获取线程池 * @return 线程池对象 */ public static ThreadPoolExecutor getThreadPool() { if (threadPool != null) { return threadPool; } else { synchronized (ThreadPoolUtil.class) { if ...
  • Java带返回值的多线程创建方式

    千次阅读 2018-04-30 09:24:38
    在Java中创建线程,一般有三种方式: 通过继承Thread类 通过实现Runable接口 通过Callable接口 第一种方法最为简单,直接创建线程对象,再启动即可,但由于Java是单继承的,所以继承了Thread之后,就不能再...
  • 【多线程 2】常见的多线程创建方式

    热门讨论 2016-10-12 20:32:24
    导读:创建线程,主要是有3种方式。而这三种方式,又可以简单的分为:无回执结果、有回执结果。 一、直接继承Thread类 package Angel; public class CreateThread extends Thread { //对run方法进行重写 ...
  • Java线程创建方式

    2012-11-19 17:34:27
    在启动线程时,一定不要使用Thread.run(),这将变成方法调用而不是启动线程,虽然Thread.start()本质上还是调用线程的run()方法 /** * Causes this thread to begin execution; the Java Virtual Machine *...
  • 今天说一下 多线程的几种创建方式及使用。 1. Thread 和 Runnable 继承 Thread 类 和实现 Runnable 接口。 这种就不举例子了。 2.线程池 现在主要有5种线程池。 //缓存线程池 ExecutorService ...
  • Java 5.0 在java.util.concurrent 提供了一个新的创建执行线程方式:Callable 接口。 Callable 接口类似于Runnable,两者都是为那些其实例可能被另一个线程执行的类设计的。但是Runnable 不会返回结果,并且无法...
  • JAVA 线程实现/创建方式 1、继承 Thread 类 Thread 类本质上是实现了 Runnable 接口的一个实例,代表一个线程的实例。启动线程的唯一方 法就是通过 Thread 类的 start()实例方法。start()方法是一个 native 方法,...
  • java中有三种创建线程方式,或者说四种 1.继承Thread类实现多线程 2.实现Runnable接口 3.实现Callable接口 4.通过线程池 线程池的工作原理:线程池可以减少创建和销毁线程的次数,从而减少系统资源的消耗,当...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 27,816
精华内容 11,126
关键字:

线程创建方式