
文章目录
Java是一种支持多线程编程的语言。多线程可以让程序同时执行多个任务,从而提高程序的效率和响应速度。在本篇博客中,我将介绍Java多线程的基础知识,包括线程的创建、启动、中断以及线程同步等方面。
什么是程序?
程序是为完成特定任务,用某种语言编程写的一组指令的集合。一组计算机能识别和执行的指令,运行于电子计算机上,满足人们某种需求的信息化工具(简单来说就是我们写的代码)
什么是进程?
进程是指运行中的程序,比如我们使用的QQ,启动qq.exe可执行程序就启动了一个线程,操作系统就会为进程分配内存空间。当我们使用迅雷,又启动了一个进程,操作系统将为迅雷分配新的内存空间。
进程是程序的一次执行过程,或正在运行的一个程序。是动态过程:有它自身的产生、存在和消亡的过程。具体关系如图所示:

打开电脑的任务管理器,即可查看电脑运行的进程

进程共有三种状态:就绪、阻塞和运行
- 就绪态:就绪状态是指程序已达到可以运行的状态,只等CPU分配资源就可以运行的状态。
- 阻塞态:当程序运行条件没有满足时,需要等待条件满足时候才能执行时所处的状态,如等待i/o操作时候,此刻的状态就叫阻塞态。
- 运行态:进程占用CPU,并在CPU上运行。即程序正在运行时所处的状态。
线程是由进程创建的,是一个进程的实体,一个进程可以有多个线程。比如:百度网盘的下载任务,一个下载任务对应一个线程,当同时下载多个任务时,相当于开启了多个线程,线程分为单线程和多线程。
在Java中线程使用有两种方式
早期计算机的 CPU 都是单核的,一个 CPU 在同一时间只能执行一个进程/线程,当系统中有多个进程/线程等待执行时,CPU 只能执行完一个再执行下一个。并发和并行是用来操作线程和进程的方式。
并发
同一时刻,多个任务交替执行,造成一种同时的错觉,并不是正在同时运行。(单核CPU实现的多任务就是并发)

并行
同一时刻,多个任务同时执行,多核CPU可以实现并行。

注意:也可能会有并发和并行同时存在
一个实现Runnable接口的类就是一个线程,通过Thread类启动。需要把实现类对象传入Thread类的构造方法中 然后通过Thread的start方法启动该Runnable实现类的线程。(因为Java是单继承机制,所以当有某个类已经继承了某个父类时,则需要用到Runnable接口)
该接口中只有一个**run()**方法,所以需要传入Thread类的构造器中进行启动
Java语言是支持多线程的,一个正在运行的Java程序可以称之为一个进程(process),在每个进程里面包含多个线程.一个Thread实例对象,就是一个线程。Thread类继承于Runnable接口

常用方法
用来控制线程优先级的范围常用的有三种:
| MAX_PRIORITY | 线程可以拥有的最大优先级(10) |
|---|---|
| MIN_PRIORITY | 线程可以拥有的最小优先级(1) |
| NORM_PRIORITY | 被分配给线程的默认优先级(5) |
注意:Thread类本身没用run方法的,而是继承Runnable接口重写得来的
使用start方法,会自动开启子线程,调用run方法。这里使用了设计模式(代理模式)
在Java中,可以通过继承Thread类或实现Runnable接口来创建一个线程。继承Thread类需要重写run()方法,而实现Runnable接口需要实现run()方法。下面是两种创建线程的示例代码:
public class MyThread extends Thread {
@Override
public void run() {
// 线程执行的代码
}
}
MyThread myThread = new MyThread();
myThread.start(); // 启动线程
public class MyRunnable implements Runnable {
@Override
public void run() {
// 线程执行的代码
}
}
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
thread.start(); // 启动线程
当执行执行代码程序时(run),会开启一个进程。之后会进入到主方法main中,会开启一个主线程(main线程)

可在控制台使用 jconsole指令监控线程执行情况,如果出现 不是内部或外部命令,也不是可运行的程序或批处理文件 。则需要检查jdk环境配置(建议手动配置)
注意:执行时需要开启需要监控的线程,才能进行查看
xx.run(); xx.start();
为什么不在主方法中直接调用run,而是通过start方法开启线程
如果使用xx.run()方法,则是主线程直接调用run方法,而此时线程的名称是main(此时的run方法就是一个普通的方法,并没有真正的启动子线程,会阻塞这里,等待run方法执行完毕,才会继续执行main主方法中代码);而使用xx.start()方法,则是通过子线程调用run方法(底层是JVM调用的,相当于开启了一个子线程)
start方法调用后,该线程并不一定会立刻马上执行,只是将线程变成了可运行状态。具体什么时候执行,取决于CPU,由CPU统一调度。

线程终止的两种情况:
中断
interrupt方法,用来中断线程,但并没有真正的结束线程,所以一般用于中断正在休眠的线程,此时调用该线程的interrupt方法,那么该线程将抛出一个InterruptedException中断异常,从而提早地终结被阻塞状态。如果线程没有被阻塞,这时调用 interrupt()将不起作用,直到执行到wait(),sleep(),join()时,才马上会抛出 InterruptedException。
如果需要中断一个线程,可以调用线程的interrupt()方法。但是,中断线程只是给线程一个中断的标志位,并不能直接终止线程的执行。线程需要自己在执行的过程中检查这个标志位,并在合适的时候终止自己的执行。下面是一个简单的中断线程的示例代码:
Thread thread = new Thread(() -> {
while (!Thread.currentThread().isInterrupted()) {
// 线程执行的代码
}
});
thread.start(); // 启动线程
// 中断线程
thread.interrupt();
Java的线程可以分为两类:User Thread(用户线程)、Daemon Thread(守护线程)
如何将一个线程设置为守护线程?
需要使用Thread类中的setDaemon方法
当主线程结束,子线程自动结束,将子线程设置为守护线程,演示如下
public class ThreadTest3 {
public static void main(String[] args) {
DaemonThread daemonThread = new DaemonThread();
daemonThread.setDaemon(true);
daemonThread.start();
for (int i = 1; i < 10; i++) {
System.out.println("主线程(用户线程)");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class DaemonThread extends Thread {
@Override
public void run() {
for (; ; ) {//无线循环
System.out.println("子线程(设置为守护线程)执行中");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Thread01 {
public static void main(String[] args) {
test t1 = new test();
t1.start();
}
}
class test extends Thread{
@Override
public void run() {
while (true){
System.out.println(Thread.currentThread().getName());//获取线程的名称
System.out.println("hello,world");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class ThreadTest {
public static void main(String[] args) {
Test test = new Test();
Thread thread = new Thread(test);
thread.start();
}
}
class Test implements Runnable{
@Override
public void run() {
while (true){
System.out.println(Thread.currentThread().getName());//获取线程的名称
System.out.println("hello,world");
try {
Thread.sleep(1000);//休眠一秒
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class ThreadTest1 {
public static void main(String[] args) {
Thread thread1 = new Thread(new T1());
thread1.start();
Thread thread2 = new Thread(new T2());
thread2.start();
}
}
class T1 implements Runnable {
int count = 0;
@Override
public void run() {
//每隔1秒输出hello,world,输出10次
while (true) {
if (count == 10) {
break;
}
System.out.println(Thread.currentThread().getName());
System.out.println("hello,world " + (++count));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class T2 implements Runnable {
int count = 0;
@Override
public void run() {
//每隔1秒输出hello,world,输出10次
while (true) {
if (count == 5) {
break;
}
System.out.println(Thread.currentThread().getName());
System.out.println("hi " + (++count));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class ThreadTest1 {
public static void main(String[] args) throws InterruptedException {
T t = new T();
t.setPriority(Thread.MIN_PRIORITY);
t.start();
for (int i = 0; i < 5; i++) {
System.out.println("hello");
Thread.sleep(1000);
}
t.interrupt();
}
}
class T extends Thread {
int count = 0;
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + "线程执行中..." + (++count));
}
try {
System.out.println("线程休眠中...");
Thread.sleep(20000);//20秒
} catch (InterruptedException e) {//当执行interrupt方法,InterruptedException会捕获到中断异常
System.out.println(Thread.currentThread().getName() + "被中断线程(interrupt)了");
}
}
}
public class ThreadTest2 {
public static void main(String[] args) throws InterruptedException {
T t = new T();
t.start();
for (int i = 0; i < 20; i++) {
System.out.println("主线程" + Thread.currentThread().getName() + "运行中...");
Thread.sleep(100);
if (i == 5) {
t.join();//子线程插队(强制成功)
// Thread.yield();//子线程插队(不一定成功)
}
}
}
}
class T extends Thread {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("子线程" + Thread.currentThread().getName() + "运行中...");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/
exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby中使用两个参数异步运行exe吗?我已经尝试过ruby命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何rubygems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除
我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r
Sinatra新手;我正在运行一些rspec测试,但在日志中收到了一堆不需要的噪音。如何消除日志中过多的噪音?我仔细检查了环境是否设置为:test,这意味着记录器级别应设置为WARN而不是DEBUG。spec_helper:require"./app"require"sinatra"require"rspec"require"rack/test"require"database_cleaner"require"factory_girl"set:environment,:testFactoryGirl.definition_file_paths=%w{./factories./test/
我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/
我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("
GivenIamadumbprogrammerandIamusingrspecandIamusingsporkandIwanttodebug...mmm...let'ssaaay,aspecforPhone.那么,我应该把“require'ruby-debug'”行放在哪里,以便在phone_spec.rb的特定点停止处理?(我所要求的只是一个大而粗的箭头,即使是一个有挑战性的程序员也能看到:-3)我已经尝试了很多位置,除非我没有正确测试它们,否则会发生一些奇怪的事情:在spec_helper.rb中的以下位置:require'rubygems'require'spork'
我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www
是否有可能:before_filter:authenticate_user!||:authenticate_admin! 最佳答案 before_filter:do_authenticationdefdo_authenticationauthenticate_user!||authenticate_admin!end 关于ruby-on-rails-before_filter运行多个方法,我们在StackOverflow上找到一个类似的问题: https://