在这里插入代码片
好了,今天终于开始重头戏了,线程。
别的不说,面试中会遇到的题目大概包括以下这些:
1、说下乐观锁悲观锁
2、object类的原生方法有哪些?
3、说下b树和b+树
4、说下hashmap实现原理,为什么线程不安全?
5、Concurrenthashmap如何实现线程安全?
6、Concurrenthashmap在jdk1.8做了哪些优化?
7、知道BIO和NIO吗?
8、仔细讲讲Websockt
9、说说Tcp断开连接的过程
10、Hashcode方法有什么作用?
11、说下equals和==的区别
12、如果判断一个链表有环,环的入口在哪
13、一共100个乒乓,每次拿一到六个,我和你轮流拿,能拿到最后一个球的人获胜,你先拿,你怎么才能赢?
14、有4个g的数据,给你256m的空间,怎么把它排序,然后写进另一个文件里?
15、知道类加载器吗?有哪些?说说类加载机制
16、你知道哪些异常?说说异常的执行过程
17、你自己如何实现一个线程池,要用什么数据结构?
18、*知道threatlocal吗?说一下原理
19、用过哪些数据库,MySQL如何保证安全?有哪些锁?
20、静态方法和实例方法的区别,在内存中存放的位置
21、说下http协议,http1.0、http1.1、http2.0有什么区别?https呢?如何保证安全的?
而这些还只是“面试”而已,就别说“笔试”了。
前面的文章说过,进程是系统分配资源的最小单位,也可叫做“任务”,而线程是系统调度的最小单位,注意区别,一个是分配一个是调度,按照我个人的暂时理解,分配是一个老师被分给一节课的时间,那么就是以“一节课”作为单位,而在一节课中老师可以合理且自由地分配各个知识点的时间占比,“一个知识点”作为单位,肯定地,知识点之间会有联结,也就是说,一个进程内的线程之间是可以共享资源的,还有,老师在一节课内至少得讲到一个知识点,换句话,每个进程至少有一个线程存在,叫做“主线程”,如果讲的知识点多了,那么肯定会有一个重点,众多知识点围绕着该重点展开,这就是主线程的作用。
以下是一个多线程程序的模板(非本人编写)
在这里插入代码片
import java.util.Random;
public class ThreadDemo {
private static class MyThread extends Thread {
@Override
比特科技
public void run() {
Random random = new Random();
while (true) {
// 打印线程名称
System.out.println(Thread.currentThread().getName());
try {
// 随机停止运行 0-9 秒
Thread.sleep(random.nextInt(10));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
MyThread t3 = new MyThread();
t1.start();
t2.start();
t3.start();
Random random = new Random();
while (true) {
// 打印线程名称
System.out.println(Thread.currentThread().getName());
try {
Thread.sleep(random.nextInt(10));
} catch (InterruptedException e) {
// 随机停止运行 0-9 秒
e.printStackTrace();
}
}
}
}
多线程的优势是增加它的运行速度,这在某些场合很吃香。
(以下亦非本人所写,模板而已)
在这里插入代码片public class ThreadAdvantage {
// 多线程并不一定就能提高速度,可以观察,count 不同,实际的运行效果也是不同的
private static final long count = 10_0000_0000;
public static void main(String[] args) throws InterruptedException {
// 使用并发方式
concurrency();
// 使用串行方式
serial();
}
private static void concurrency() throws InterruptedException {
long begin = System.nanoTime();
// 利用一个线程计算 a 的值
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
int a = 0;
for (long i = 0; i < count; i++) {
a--;
}
}
});
thread.start();
// 主线程内计算 b 的值
int b = 0;
for (long i = 0; i < count; i++) {
b--;
}
// 等待 thread 线程运行结束
thread.join();
// 统计耗时
long end = System.nanoTime();
double ms = (end - begin) * 1.0 / 1000 / 1000;
System.out.printf("并发: %f 毫秒%n", ms);
}
private static void serial() {
// 全部在主线程内计算 a、b 的值
long begin = System.nanoTime();
int a = 0;
for (long i = 0; i < count; i++) {
a--;
}
int b = 0;
for (long i = 0; i < count; i++) {
b--;
}
long end = System.nanoTime();
double ms = (end - begin) * 1.0 / 1000 / 1000;
System.out.printf("串行: %f 毫秒%n", ms);
}
}
以下是对比结果:
并发: 399.651856 毫秒
串行: 720.616911 毫秒
创建线程有两种主要方法,一是通过Thread继承,二是通过Runnable接口,还有更多变形,但不很常见,例如lamba表达式和匿名类创建,若一次性全写出来也太过冗长,下次一定。
下面是代码块(现在是我写的了)
在这里插入代码片
1.class MyThread extends Thread {
@Override
public void run() {
System.out.println("这里是线程运行的代码");
}
}
MyThread t = new MyThread();
t.start(); // 线程开始运行
2.class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "这里是线程运行的代码");
}
}
Thread t = new Thread(new MyRunnable());
t.start();// 线程开始运行
在这里插入代码片
比之前文章长很多,是不?
但这其实还早着呢…