51、启动一个线程是用run()还是start()?
启动线程肯定要用start()方法。
start()方法:用来启动一个线程,这时此线程处于就绪状态,然后通过调用此线程的run()方法来完成线程的运行操作。(当用start()开始一个线程后,线程就进入就绪状态,使线程所代表的虚拟处理机处于可运行状态,这意味着它可以由JVM调度并执行。这并不意味着线程就会立即运行。当cpu分配给它时间时,才开始执行run()方法(如果有的话))。
run()方法:这只是一个方法,直接调用该方法只是把该方法的函数体给执行了一遍,并没真正启动一个线程。
52、当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法?
分几种情况:
1. 该对象其他方法前是否加了synchronized关键字,如果没加,则能。
2. 如果其他个方法都加了synchronized关键字,并且内部有调用wait,则能
3. 如果其他个方法都加了synchronized关键字,并且内部没有调用wait,则不能。
4. 如果其他方法是static,它用的同步锁是当前类的字节码,与非静态的方法不能同步,因为非静态的方法用的是this。
53、线程的基本概念、线程的基本状态以及状态之间的关系
进程中独立运行的程序片段叫做线程。
Java中的线程有四种状态分别是:运行、就绪、阻塞、死亡。
【扩展】进程与线程的区别:(面试题)
1.进程有独立的进程空间,进程中的数据存放空间(堆空间和栈空间)是独立的。
2.线程的堆空间是共享的,栈空间是独立的,线程消耗的资源也比进程小,相互之间可以影响的。
54、简述synchronized和java.util.concurrent.locks.Lock的异同?
主要相同点:Lock能完成synchronized所实现的所有功能
主要不同点:Lock有比synchronized更精确的线程语义和更好的性能。synchronized会自动释放锁,而Lock一定要求程序员手工释放,并且必须在finally从句中释放。Lock还有更强大的功能,例如,它的tryLock方法可以非阻塞方式去拿锁。
55、设计4个线程,其中两个线程每次对j增加1,另外两个线程对j每次减少
class ThreadTest {
private int j;
public static void main(String args[]) {
ThreadTest tt = new ThreadTest();
Inc inc = tt.new Inc();
Dec dec = tt.new Dec();
for (int i = 0; i < 2; i++) {
Thread t = new Thread(inc);
t.start();
t = new Thread(dec);
t.start();
}
}
private synchronized void inc() {
j++;
System.out.println(Thread.currentThread().getName() + "-inc:" + j);
}
private synchronized void dec() {
j--;
System.out.println(Thread.currentThread().getName() + "-dec:" + j);
}
class Inc implements Runnable {
public void run() {
for (int i = 0; i < 100; i++) {
inc();
}
}
}
class Dec implements Runnable {
public void run() {
for (int i = 0; i < 100; i++) {
dec();
}
}
}
}
56、子线程循环10次,接着主线程循环100,接着又回到子线程循环10次,接着再回到主线程又循环100,如此循环50次,请写出程序。
public class TraditionalThreadCommunication {
public static void main(String[] args) {
final Business bussiness = new Business();
new Thread(
new Runnable(){
public void run() {
for(int j=1; j<=50;j++){
bussiness.sub(j);
}
}
}
).start();
new Thread(
new Runnable(){
public void run() {
for(int j=1; j<=50;j++){
bussiness.main(j);
}
}
}
).start();
}
}
class Business{
boolean bShouldSub = true;
public synchronized void sub(int j){
if(!bShouldSub){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for(int i=1;i<=10;i++){
System.out.println("子线程循环。。。" + i);
}
bShouldSub = false;
this.notify();
}
public synchronized void main(int j){
if(bShouldSub){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for(int i=1;i<=30;i++){
System.out.println("主线程循环。。。" + i);
}
bShouldSub = true;
this.notify(); // 喚醒。
}
}
下面使用jdk5中的并发库来实现的:
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ConditionThreadCommunication {
public static void main(String[] args) {
final Business business = new Business();
/*子线程*/
new Thread(new Runnable(){
public void run() {
for(int i = 1; i <= 50; i++){
business.sub(i);
}
}
}).start();
/*主线程*/
for(int i = 1; i <= 50; i++){
business.main(i);
}
}
static class Business {//处理线程安全归为一类,这样用的就是同一把同步锁
private boolean subShouldRun = true; //当为true时子线程执行,当为false时主线程执行
private Lock lock = new ReentrantLock();//创建一把锁
private Condition condition = lock.newCondition();//创建condition操作等待与唤醒操作
public void sub(int i)
{
lock.lock();//打开锁
try
{
while(!subShouldRun)
{
try {
//this.wait();//等待线程
condition.await();//condition等待
} catch (Exception e) {
e.printStackTrace();
}
}
for(int j = 1; j <= 10; j++)
{
System.out.println("sub Thread sequence of " + j + ", loop of " + i);
}
subShouldRun = false;
//this.notify();//唤醒线程
condition.signal();//condition唤醒线程
}finally
{
lock.unlock();//关闭锁
}
}
public void main(int i)
{
lock.lock();//打开锁
try
{
while(subShouldRun)
{
try {
//this.wait();
condition.await();
} catch (Exception e) {
e.printStackTrace();
}
}
for(int j = 1; j <= 100; j++)
{
System.out.println("main Thread sequence of " + j + ", loop of " + i);
}
subShouldRun = true;
//this.notify();
condition.signal();
}finally
{
lock.unlock();//关闭锁
}
}
}
}
57、介绍Collection框架的结构
Collection
|-----List 有顺序可重复
|-----ArrayList
是数组实现 它是线程不安全的。它每一次添加后都会增长50%长度。它在执行查找操作时效率比较高
|-----LinkedList 是链表实现,它在执行修改或插入时效率比较高。 它是线程不安全的。
|-----Vector 它也是数组实现,它是线程安全的 它每一次添加后都会增长100%长度。无论是查找还是修改删除操作效率都比较低。
|-----Set 无顺序不重复
|----HashSet 底层实现是使用hash表,特点是无顺序不可重复;HashSet维护元素的唯一性是使用元素的hashCode与equals实现的。
|------LinkedHashSet 它的特点保证添加时的顺序与取出时的顺序一样。
|-----TreeSet 特点:有顺序的不重复,底层实现是使用二叉树
【扩展】类集框架的完整结构(Collection)
框架的完整结构(Collection)
1.类集框架最大的接口:Collection、Map、Iterator、Enumeration
2.Collection:存放单值
|- List:允许有重复内容,有序
|- ArrayList:异步处理,新的操作类,非线程安全。
|- Vector:同步处理,旧的操作类,线程安全。支持Enumeration输出
|- Set:不允许有重复内容,无序,靠hashCoke()和equals()进行重复的严重
|- HashSet:无序存放
|- TreeSet:有序存放,安Comparable排序
3.Map:存放一对值
|- HashMap:新的类,异步处理,非线程安全,允许有null
|- Hashtable:旧的类,同步处理,线程安全,不允许有null
|- Properties:属性操作类
|- TreeMap:有序排列,按key排序,根据Comparable指定排序规则
4.Iterator:
|- 迭代输出,依靠Collection接口中的iterator方法输出,是新的输出标准
5.Enumeration:旧的输出标准
58、Collection框架中实现比较要实现什么接口
comparable/comparator
【扩展】comparable与comparator的区别
(1)Comparable 用作默认的比较方式 ,需要覆盖compareTo方法。
Comparator 用作自定义的比较方式,当默认的比较方式不适用时或者没有提供默认的比较方式,使用Comparator, 需要覆盖compare方法
(2)comparable属于java.lang包,comparator属于java.util包
(3)像Arrays和Collections中的排序方法,当不指定Comparator时使用的就是默认排序方式,也就是使用Comparable。指定Comparator时就是使用提供的比较器。
sort(Object[]) 所有的对象都必须实现Comparable接口,它用来确定对象之间的大小关系
sort(Object[], Comparator) 对象不必实现Comparable接口,由Comparator来确定对象之间的大小关系。
59、ArrayList和Vector的区别
(1)ArrayList :是数组实现 它是线程不安全的。它每一次添加后都会增长50%长度.它在执行查找操作时效率比较高;
(2)Vector 它也是数组实现,它是线程安全的 它每一次添加后都会增长100%长度,无论是查找还是修改删除操作效率都比较低。(同步性和数据增长)
60、HashMap和Hashtable的区别
HashMap:新的类,异步处理,非线程安全,允许有null
Hashtable:旧的类,同步处理,线程安全,不允许有null