Hello,Thread 系统管理员 2022-01-12 16:19 243阅读 0赞 创建线程的三种方法,线程的生命周期,sleep,yield,join,wait 和notify,线程组,守护线程,线程的优先级 ◆ 如何创建线程 ◆ Java 中创建线程的方法有三种: 1. 继承 Thread 类创建线程 新建一个类继承 Thread 类,并重写 Thread 类的 run() 方法。 创建 Thread 子类的实例。 调用该子类实例的 start() 方法启动该线程。 代码举例如下: <table> <tbody> <tr> <td><pre><span>1</span><br><span>2</span><br><span>3</span><br><span>4</span><br><span>5</span><br><span>6</span><br><span>7</span><br><span>8</span><br><span>9</span><br><span>10</span><br><span>11</span><br><span>12</span><br></pre></td> <td><pre><span><span>public</span> <span><span>class</span> <span>HelloThread1</span> </span>{ </span><br><span> <span>static</span> <span><span>class</span> <span>ThreadDemo</span> <span>extends</span> <span>Thread</span> </span>{ </span><br><span> <span>@Override</span></span><br><span> <span><span>public</span> <span>void</span> <span>run</span><span>()</span> </span>{ </span><br><span> System.out.println(<span>"Hello Thread"</span>);</span><br><span> }</span><br><span> }</span><br><span> <span><span>public</span> <span>static</span> <span>void</span> <span>main</span><span>(String[] args)</span> </span>{ </span><br><span> ThreadDemo threadDemo = <span>new</span> ThreadDemo();</span><br><span> threadDemo.start();</span><br><span> }</span><br><span>}</span><br></pre></td> </tr> </tbody> </table> 2.实现 Runnable 接口创建线程: 创建一个类实现 Runnable 接口,并重写该接口的 run() 方法。 创建该实现类的实例。 将该实例传入 Thread(Runnable r) 构造方法中创建 Thread 实例。 调用该 Thread 线程对象的 start() 方法。 代码举例如下: <table> <tbody> <tr> <td><pre><span>1</span><br><span>2</span><br><span>3</span><br><span>4</span><br><span>5</span><br><span>6</span><br><span>7</span><br><span>8</span><br><span>9</span><br><span>10</span><br><span>11</span><br><span>12</span><br></pre></td> <td><pre><span><span>public</span> <span><span>class</span> <span>HelloThread1</span> </span>{ </span><br><span> <span>static</span> <span><span>class</span> <span>ThreadDemo</span> <span>extends</span> <span>Thread</span> </span>{ </span><br><span> <span>@Override</span></span><br><span> <span><span>public</span> <span>void</span> <span>run</span><span>()</span> </span>{ </span><br><span> System.out.println(<span>"Hello Thread"</span>);</span><br><span> }</span><br><span> }</span><br><span> <span><span>public</span> <span>static</span> <span>void</span> <span>main</span><span>(String[] args)</span> </span>{ </span><br><span> ThreadDemo threadDemo = <span>new</span> ThreadDemo();</span><br><span> threadDemo.start();</span><br><span> }</span><br><span>}</span><br></pre></td> </tr> </tbody> </table> 1. 使用 Callable 和 FutureTask 创建线程: 创建一个类实现 Callable 接口,并重写 call() 方法。 创建该 Callable 接口实现类的实例。 将 Callable 的实现类实例传入 FutureTask(Callable callable) 构造方法中创建 FutureTask 实例。 将 FutureTask 实例传入 Thread(Runnable r) 构造方法中创建 Thread 实例。 调用该 Thread 线程对象的 start() 方法。 调用 FutureTask 实例对象的 get() 方法获取返回值。 代码举例如下: <table> <tbody> <tr> <td><pre><span>1</span><br><span>2</span><br><span>3</span><br><span>4</span><br><span>5</span><br><span>6</span><br><span>7</span><br><span>8</span><br><span>9</span><br><span>10</span><br><span>11</span><br><span>12</span><br><span>13</span><br><span>14</span><br><span>15</span><br><span>16</span><br><span>17</span><br><span>18</span><br><span>19</span><br><span>20</span><br></pre></td> <td><pre><span><span>public</span> <span><span>class</span> <span>HelloThread3</span> </span>{ </span><br><span> <span>static</span> <span><span>class</span> <span>ThreadDemo</span> <span><span>implements</span> <span>Callable</span></span><<span>String</span>> </span>{ </span><br><span> @Override</span><br><span> <span>public</span> <span>String</span> call() { </span><br><span> System.out.println(<span>"Hello Thread"</span>);</span><br><span> <span>return</span> <span>"Callable return value"</span>;</span><br><span> }</span><br><span> }</span><br><span> <span>public</span> <span>static</span> void main(<span>String</span>[] args) { </span><br><span> ThreadDemo threadDemo = <span>new</span> <span>ThreadDemo</span>();</span><br><span> FutureTask<<span>String</span>> futureTask = <span>new</span> <span>FutureTask</span><<span>String</span>>(threadDemo);</span><br><span> Thread thread = <span>new</span> <span>Thread</span>(futureTask);</span><br><span> thread.start();</span><br><span> <span>try</span> { </span><br><span> System.out.println(futureTask.<span>get</span>());</span><br><span> } <span>catch</span> (Exception e) { </span><br><span> e.printStackTrace();</span><br><span> }</span><br><span> }</span><br><span>}</span><br></pre></td> </tr> </tbody> </table> ◆ 线程的生命周期 ◆ 关于Java中线程的生命周期,首先看一下下面这张图: 上图中基本上囊括了Java中多线程各重要知识点。掌握了上图中的各知识点,Java中的多线程也就基本上掌握了。 ◆ 线程的基本状态 ◆ 新建状态(New):当线程对象对创建后,即进入了新建状态,如:Thread t = new MyThread(); 就绪状态(Runnable):当调用方法t.start()时,线程即进入就绪状态。处于就绪状态的线程,只是说明此线程已经做好了准备,随时等待CPU调度执行,并不是说执行了t.start()此线程立即就会执行;同样还有几种情况会进行就绪状态,请参见上图。 运行状态(Running):当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。注:就绪状态是进入到运行状态的唯一入口,也就是说,线程要想进入运行状态执行,首先必须处于就绪状态中; 阻塞状态(Blocked):处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才 有机会再次被CPU调用以进入到运行状态。根据阻塞产生的原因不同,阻塞状态又可以分为三种:请参见上图。 死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。 ◆ 线程的基本操作 ◆ sleep:使当前线程休眠指定毫秒 yield:使当前线程让出CPU,从运行状态转到可运行状态。注意仅仅是让出,让出之后也会加入到抢占资源的队伍中。 join:把指定的线程加入到当前线程,比如在线程B中调用了线程A的Join()方法,直到线程A执行完毕后,才会继续执行线程B 线程停止: Thread本身提供了一个stop方法,但是这个不推荐使用。因为使用stop的时候会暴力终止线程,从而造成数据不一致。 优雅的停止线程的代码举例如下: <table> <tbody> <tr> <td><pre><span>1</span><br><span>2</span><br><span>3</span><br><span>4</span><br><span>5</span><br><span>6</span><br><span>7</span><br><span>8</span><br><span>9</span><br><span>10</span><br><span>11</span><br><span>12</span><br><span>13</span><br><span>14</span><br><span>15</span><br><span>16</span><br><span>17</span><br><span>18</span><br><span>19</span><br><span>20</span><br><span>21</span><br><span>22</span><br><span>23</span><br><span>24</span><br><span>25</span><br><span>26</span><br><span>27</span><br></pre></td> <td><pre><span><span>public</span> <span><span>class</span> <span>StopThread</span> </span>{ </span><br><span> <span>static</span> <span><span>class</span> <span>ThreadDemo</span> <span>extends</span> <span>Thread</span> </span>{ </span><br><span> <span>volatile</span> <span>boolean</span> stopMe = <span>false</span>;</span><br><span> <span><span>public</span> <span>void</span> <span>stopMe</span><span>()</span></span>{ </span><br><span> <span>this</span>.stopMe=<span>true</span>;</span><br><span> }</span><br><span> <span>@Override</span></span><br><span> <span><span>public</span> <span>void</span> <span>run</span><span>()</span> </span>{ </span><br><span> <span>while</span> (<span>true</span>) { </span><br><span> <span>if</span> (stopMe) { </span><br><span> System.out.println(<span>"程序结束"</span>);</span><br><span> <span>break</span>;</span><br><span> }</span><br><span> <span>try</span> { </span><br><span> Thread.sleep(<span>1000</span>);</span><br><span> } <span>catch</span> (InterruptedException e) { </span><br><span> e.printStackTrace();</span><br><span> }</span><br><span> }</span><br><span> }</span><br><span> }</span><br><span> <span><span>public</span> <span>static</span> <span>void</span> <span>main</span><span>(String[] args)</span> </span>{ </span><br><span> ThreadDemo threadDemo = <span>new</span> ThreadDemo();</span><br><span> threadDemo.start();</span><br><span> threadDemo.stopMe();</span><br><span> }</span><br><span>}</span><br></pre></td> </tr> </tbody> </table> 以一个volatile修饰的变量stopMe来控制线程的停止。 线程中断: 线程中断的相关方法分别是这三个 <table> <tbody> <tr> <td><pre><span>1</span><br><span>2</span><br><span>3</span><br></pre></td> <td><pre><span><span>public</span> <span><span>void</span> <span>interrupt</span><span>()</span> </span>; <span>//中断线程</span></span><br><span><span>public</span> <span><span>boolean</span> <span>isInterrupted</span><span>()</span></span>; <span>//判断线程是否被中断</span></span><br><span><span>public</span> <span>static</span> <span><span>boolean</span> <span>interrupted</span><span>()</span></span>; <span>//判断线程是否被中断,并清除当前中断状态</span></span><br></pre></td> </tr> </tbody> </table> 线程中断的代码举例如下: <table> <tbody> <tr> <td><pre><span>1</span><br><span>2</span><br><span>3</span><br><span>4</span><br><span>5</span><br><span>6</span><br><span>7</span><br><span>8</span><br><span>9</span><br><span>10</span><br><span>11</span><br><span>12</span><br><span>13</span><br><span>14</span><br><span>15</span><br><span>16</span><br><span>17</span><br><span>18</span><br><span>19</span><br><span>20</span><br><span>21</span><br><span>22</span><br><span>23</span><br></pre></td> <td><pre><span><span>public</span> <span><span>class</span> <span>InterruptThread</span> </span>{ </span><br><span> <span>static</span> <span><span>class</span> <span>ThreadDemo</span> <span>extends</span> <span>Thread</span> </span>{ </span><br><span> <span>@Override</span></span><br><span> <span><span>public</span> <span>void</span> <span>run</span><span>()</span> </span>{ </span><br><span> <span>while</span> (<span>true</span>) { </span><br><span> <span>if</span> (Thread.currentThread().isInterrupted()) { </span><br><span> System.out.println(<span>"程序结束"</span>);</span><br><span> <span>break</span>;</span><br><span> }</span><br><span> <span>try</span> { </span><br><span> Thread.sleep(<span>1000</span>);</span><br><span> } <span>catch</span> (InterruptedException e) { </span><br><span> e.printStackTrace();</span><br><span> }</span><br><span> }</span><br><span> }</span><br><span> }</span><br><span> <span><span>public</span> <span>static</span> <span>void</span> <span>main</span><span>(String[] args)</span> </span>{ </span><br><span> ThreadDemo threadDemo = <span>new</span> ThreadDemo();</span><br><span> threadDemo.start();</span><br><span> threadDemo.interrupt();</span><br><span> }</span><br><span>}</span><br></pre></td> </tr> </tbody> </table> wait 和notify 这两个方法是JDK为了支持多线程之间的协作而提供的。 当在线程A中调用了obj.wait()方法时,线程A会停止执行进入等待状态。直到其他线程调用obj.notify()时才会进入阻塞状态继而等待获取锁。 请看下方示例代码 <table> <tbody> <tr> <td><pre><span>1</span><br><span>2</span><br><span>3</span><br><span>4</span><br><span>5</span><br><span>6</span><br><span>7</span><br><span>8</span><br><span>9</span><br><span>10</span><br><span>11</span><br><span>12</span><br><span>13</span><br><span>14</span><br><span>15</span><br><span>16</span><br><span>17</span><br><span>18</span><br><span>19</span><br><span>20</span><br><span>21</span><br><span>22</span><br><span>23</span><br><span>24</span><br><span>25</span><br><span>26</span><br><span>27</span><br><span>28</span><br><span>29</span><br><span>30</span><br><span>31</span><br><span>32</span><br><span>33</span><br><span>34</span><br><span>35</span><br><span>36</span><br><span>37</span><br><span>38</span><br><span>39</span><br><span>40</span><br><span>41</span><br><span>42</span><br><span>43</span><br><span>44</span><br><span>45</span><br><span>46</span><br></pre></td> <td><pre><span>public <span><span>class</span> <span>WaitNotifyThread</span> </span>{ </span><br><span> public static <span>Object</span> obj = <span>new</span> <span>Object</span>();</span><br><span></span><br><span> static <span><span>class</span> <span>WaitThreadDemo</span> <span>extends</span> <span>Thread</span> </span>{ </span><br><span> <span>@Override</span></span><br><span> public void run() { </span><br><span> synchronized (obj) { </span><br><span> <span>try</span> { </span><br><span> <span>System</span>.out.println(<span>"WaitThread wait,time="</span> + <span>System</span>.currentTimeMillis());</span><br><span> obj.wait();</span><br><span> } <span>catch</span> (<span>InterruptedException</span> e) { </span><br><span> e.printStackTrace();</span><br><span> }</span><br><span> <span>System</span>.out.println(<span>"WaitThread end,time="</span> + <span>System</span>.currentTimeMillis());</span><br><span> }</span><br><span> }</span><br><span> }</span><br><span></span><br><span> static <span><span>class</span> <span>NotifyThreadDemo</span> <span>extends</span> <span>Thread</span> </span>{ </span><br><span> <span>@Override</span></span><br><span> public void run() { </span><br><span> synchronized (obj) { </span><br><span> <span>System</span>.out.println(<span>"NotifyThread notify,time="</span> + <span>System</span>.currentTimeMillis());</span><br><span> obj.notify();</span><br><span> <span>try</span> { </span><br><span> <span>Thread</span>.sleep(<span>2000</span>);</span><br><span> } <span>catch</span> (<span>InterruptedException</span> e) { </span><br><span> e.printStackTrace();</span><br><span> }</span><br><span> <span>System</span>.out.println(<span>"NotifyThread end,time="</span> + <span>System</span>.currentTimeMillis());</span><br><span> }</span><br><span> }</span><br><span> }</span><br><span></span><br><span> public static void main(<span>String</span>[] args) { </span><br><span> <span>WaitThreadDemo</span> waitThreadDemo = <span>new</span> <span>WaitThreadDemo</span>();</span><br><span> <span>NotifyThreadDemo</span> notifyThreadDemo = <span>new</span> <span>NotifyThreadDemo</span>();</span><br><span> waitThreadDemo.start();</span><br><span> <span>try</span> { </span><br><span> <span>Thread</span>.sleep(<span>100</span>);</span><br><span> } <span>catch</span> (<span>InterruptedException</span> e) { </span><br><span> e.printStackTrace();</span><br><span> }</span><br><span> notifyThreadDemo.start();</span><br><span> }</span><br><span>}</span><br></pre></td> </tr> </tbody> </table> 在上方的代码中,Wait线程会首先获取到obj的锁,当它执行wait方法时就会释放obj的锁并进入等待状态。这个时候Notify线程可以获取到obj的锁,并且唤醒Wait线程,但是因为此时Notify线程是睡眠了2秒钟之后才释放的obj的锁,所以Wait线程获取锁的时候Notify线程已经执行完毕了。 此程序的运行结果: <table> <tbody> <tr> <td><pre><span>1</span><br><span>2</span><br><span>3</span><br><span>4</span><br></pre></td> <td><pre><span>WaitThread wait,<span>time</span>=1553088237753</span><br><span>NotifyThread notify,<span>time</span>=1553088237862</span><br><span>NotifyThread end,<span>time</span>=1553088239867</span><br><span>WaitThread end,<span>time</span>=1553088239867</span><br></pre></td> </tr> </tbody> </table> suspen和resume 它们两个的功能是挂起线程和继续执行,被suspen挂起的线程必须被resume唤醒才可以继续执行。乍看起来 可以实现wait和notify的功能,不过我可不推荐你使用它们,和wait之后会释放锁不同,suspen挂起之后依然会持有锁,这个可就非常危险了。 线程组 在一个系统中如果线程数量众多而又功能比较一致,就可以把这些线程放到一个线程组里。 线程组示例代码: <table> <tbody> <tr> <td><pre><span>1</span><br><span>2</span><br><span>3</span><br><span>4</span><br><span>5</span><br><span>6</span><br><span>7</span><br><span>8</span><br><span>9</span><br><span>10</span><br><span>11</span><br><span>12</span><br><span>13</span><br><span>14</span><br><span>15</span><br><span>16</span><br><span>17</span><br><span>18</span><br><span>19</span><br><span>20</span><br><span>21</span><br><span>22</span><br></pre></td> <td><pre><span><span>public</span> <span><span>class</span> <span>ThreadGroupDemo</span> </span>{ </span><br><span> <span>static</span> <span><span>class</span> <span>ThreadDemo</span> <span><span>extends</span> <span>Thread</span></span> </span>{ </span><br><span> @Override</span><br><span> <span>public</span> void run() { </span><br><span> <span>while</span> (<span>true</span>){ </span><br><span> System.out.println(<span>"I am "</span>+Thread.currentThread().getThreadGroup().getName()+<span>"-"</span>+Thread.currentThread().getName());</span><br><span> <span>try</span> { </span><br><span> sleep(<span>2000</span>);</span><br><span> } <span>catch</span> (InterruptedException e) { </span><br><span> e.printStackTrace();</span><br><span> }</span><br><span> }</span><br><span> }</span><br><span> }</span><br><span> <span>public</span> <span>static</span> void main(<span>String</span>[] args) { </span><br><span> ThreadGroup threadGroup=<span>new</span> <span>ThreadGroup</span>(<span>"groupDemo"</span>);</span><br><span> Thread t1=<span>new</span> <span>Thread</span>(threadGroup,<span>new</span> <span>ThreadDemo</span>(),<span>"t1"</span>);</span><br><span> Thread t2=<span>new</span> <span>Thread</span>(threadGroup,<span>new</span> <span>ThreadDemo</span>(),<span>"t2"</span>);</span><br><span> t1.start();</span><br><span> t2.start();</span><br><span> }</span><br><span>}</span><br></pre></td> </tr> </tbody> </table> 守护线程 在线程的世界里,由我们自己创建的线程叫用户线程。而一些系统创建的线程,如垃圾回收线程等被称之为守护线程,如果想要把一个用户线程设置为守护线程可以在线程的调用线程的start方法前设置线程的daemon属性为true; <table> <tbody> <tr> <td><pre><span>1</span><br></pre></td> <td><pre><span><span>t1</span>.setDaemon(true)<span>;</span></span><br></pre></td> </tr> </tbody> </table> 当一个程序中只有守护线程的时候这个程序也就要结束了。 线程的优先级 Java中的线程可以有自己的优先级,优先级高的线程在进行资源抢占的时候往往会更有优势。线程饥饿现象就是由于线程的优先级低无法抢占资源而引起的。 在Java中线程的优先级可以设置的范围是1到10之间,数字越大优先级越高。Java线程创建默认的优先级是5,我们可以线程start之前通过如下方式设置线程的优先级。 <table> <tbody> <tr> <td><pre><span>1</span><br></pre></td> <td><pre><span><span>t1</span>.setPriority(<span>1</span>)<span>;</span></span><br></pre></td> </tr> </tbody> </table> 本文所有源码[https://github.com/shiyujun][https_github.com_shiyujun] -------------------- ![微信图片\_20190308165816.jpg][20190308165816.jpg] 转载于:https://blog.51cto.com/12980017/2367004 [https_github.com_shiyujun]: https://github.com/shiyujun/syj-study-demo/tree/master/src/main/java/cn/shiyujun/thread/hellothread [20190308165816.jpg]: https://s1.51cto.com/images/20190322/1553216933943496.jpg?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=
还没有评论,来说两句吧...